测试代码:
class Foo {
private int f1 = 2;
private boolean f2 = true;
private String f3 = "foo";
private R f4 = new R("foo");
protected Foo() {
System.out.println("Foo.<ctor>()");
dump();
}
protected void dump() {
System.out.println("Foo.dump()");
System.out.println(" Foo.f1=" + this.f1);
System.out.println(" Foo.f2=" + this.f2);
System.out.println(" Foo.f3=" + this.f3);
System.out.println(" Foo.f4=" + this.f4);
}
}
class Bar extends Foo {
private int f1 = 5;
private boolean f2 = false;
private String f3 = "bar";
private R f4 = new R("bar");
public Bar() {
System.out.println("Bar.<ctor>()");
dump();
}
@Override
protected void dump() {
super.dump();
System.out.println("Bar.dump()");
System.out.println(" Bar.f1=" + this.f1);
System.out.println(" Bar.f2=" + this.f2);
System.out.println(" Bar.f3=" + this.f3);
System.out.println(" Bar.f4=" + this.f4);
}
}
class R {
private final String name;
public R(String name) {
System.out.println("R.<ctor>("" + name + "")");
this.name = name;
}
public String toString() {
return "R("" + this.name + "")";
}
}
public class TestVirtual {
public static void main(String[] argv) {
Bar b = new Bar();
}
}
执行结果:
R.<ctor>("foo")
Foo.<ctor>()
Foo.dump()
Foo.f1=2
Foo.f2=true
Foo.f3=foo
Foo.f4=R("foo")
Bar.dump()
Bar.f1=0
Bar.f2=false
Bar.f3=null
Bar.f4=null
R.<ctor>("bar")
Bar.<ctor>()
Foo.dump()
Foo.f1=2
Foo.f2=true
Foo.f3=foo
Foo.f4=R("foo")
Bar.dump()
Bar.f1=5
Bar.f2=false
Bar.f3=bar
Bar.f4=R("bar")
结论:
1 java在基类构造器中调用虚方法,被调用的是实际类型的方法。
2 java执行构造器的顺序是:
- Object类的构造器。
- 初始化基类字段。
- 执行基类构造器。
- 初始化子类字段。
- 执行子类构造器。
3 如果未在定义时为字段设置初始值,那么数值类型的字段被初始化为0,boolean类型的字段被初始化为false,引用类型的字段被初始化为null。
4 如果在定义时为字段设置初始值,同时在构造器中为字段设置初始值,那么字段会被初始化两次:首先被初始化为定义时的值,然后在构造器中再次被初始化。