Java-java 继承中的问题
class Base
{
String name = "base";
public Base() {
print();
tell();
}
public void print()
{
System.out.println("Base print "+name);
}
public void tell()
{
System.out.println("Base tell "+name);
}
}
public class Derived extends Base {
String name = "derived";
public Derived() {
print();
tell();
}
public void print()
{
System.out.println("Derived print "+name);
}
public void tell()
{
System.out.println("Derived tell "+name);
}
public static void main(String[] args)
{
new Derived();
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这主要涉及对象构造的过程,具体可以看Java语言定义中的12.5. Creation of New Class Instances。
简单来说,子类构造器会先调用父类的构造器,父类的构造器返回之后再给实例变量赋值(在这之前是0、null等默认值),然后继续完成构造器里后续的语句。
而且值得注意的是两点:
如果子类重载了父类的方法,在父类的构造器里实际调用的是重载后的方法,这意味着在子类还没构造完成就可以调用子类的方法。
同名的实例变量在父类和子类里是分开的。
稍微改改代码,不要把两个方法都重载了(没重载print):
class Base
{
String name = "base";
public Base() {
print();
tell();
}
public void print()
{
System.out.println("Base print "+name);
}
public void tell()
{
System.out.println("Base tell "+name);
}
}
public class Derived extends Base {
String name = "derived";
public Derived() {
print();
tell();
}
public void tell()
{
System.out.println("Derived tell "+name);
}
public static void main(String[] args)
{
new Derived();
}
}
结果是这样的
Base print base
Derived tell null
Base print base
Derived tell derived
前两个输出是在父类构造器。Base的构造器会调用他的父类(Object)的构造器,Obejct构造完成之后,Base的实例变量被初始化赋值,然后再调用print()和tell(),而且这个tell()是Derived的tell(),这时Dervied还没构造完成,Derived的name还是null。
也可以反编译看一下(为了方便阅读, 省略了无关的部分, 并调了顺序):
// from Derived.class
public static void main(java.lang.String[] args);
0 new Derived [1]
3 invokespecial Derived() [56]
6 return
public Derived();
0 aload_0 [this]
1 invokespecial Base() [10]
4 aload_0 [this]
5 ldc <String "derived"> [12]
7 putfield Derived.name : java.lang.String [14]
10 aload_0 [this]
11 invokevirtual Derived.print() : void [16]
14 aload_0 [this]
15 invokevirtual Derived.tell() : void [19]
18 return
//from Base.class
public Base();
0 aload_0 [this]
1 invokespecial java.lang.Object() [10]
4 aload_0 [this]
5 ldc <String "base"> [12]
7 putfield Base.name : java.lang.String [14]
10 aload_0 [this]
11 invokevirtual Base.print() : void [16]
14 aload_0 [this]
15 invokevirtual Base.tell() : void [19]
18 return
可以看到, main函数里调用了Derived的构造函数,Derived的构造函数里首先会调用Base的构造函数.
注意看! 这里只生成了一个对象实例, 即main里new的那个Derived, 在Derived和Base的构造函数里的'this'都是这同一个Derived对象.
ok, 接下来就是主要的地方了, 在Base构造函数的这里:
11 invokevirtual Base.print() : void [16],
这里似乎调用了Base的print(), 按理应该打印出"Base print base"; BUT,
invokevritual这个指令是按照 当前对象实例(就是10 aload_0 [this] 的这个this)的类来操作的, JVM Spec7这么说: 先在对象实例类里找这个方法, 没有的话递归在父类找.
所以这里实际调用的是Derived.print(), 如下:
public void print();
0 getstatic java.lang.System.out : java.io.PrintStream [26]
3 new java.lang.StringBuilder [32]
6 dup
7 ldc <String "Derived print "> [34]
9 invokespecial java.lang.StringBuilder(java.lang.String) [36]
12 aload_0 [this]
13 getfield Derived.name : java.lang.String [14]
16 invokevirtual java.lang.StringBuilder.append(java.lang.String) : java.lang.StringBuilder [39]
19 invokevirtual java.lang.StringBuilder.toString() : java.lang.String [43]
22 invokevirtual java.io.PrintStream.println(java.lang.String) : void [47]
25 return
看第13行,要去拿Derived.name; 而实际上这里Derived.name还没有赋值(从Base构造函数返回后才回去赋值, 看Derived的构造函数).
所以打印出了:
Derived print null