测试代码:
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 如果在定义时为字段设置初始值,同时在构造器中为字段设置初始值,那么字段会被初始化两次:首先被初始化为定义时的值,然后在构造器中再次被初始化。