难度等级: 中等
预测以下 Java 程序的输出:
// 文件名: Test.java class Test { int x = 10; public static void main(String[] args) { Test t = new Test(); System.out.println(t.x); } }
该程序运行良好并打印 10。在 Java 中,成员可以使用类声明进行初始化。当初始化值可用并且初始化可以放在一行时,此初始化工作得很好(有关更多详细信息,请参阅此)。例如,以下程序也可以正常工作。
// 文件名: Test.java class Test { int y = 2; int x = y+2; public static void main(String[] args) { Test m = new Test(); System.out.println("x = " + m.x + ", y = " + m.y); } }
上述程序的输出是“x = 4, y = 2”。y 首先被初始化,然后 x 被初始化为 y + 2。所以 x 的值变成了 4。
当一个成员在类声明和构造函数中都被初始化时会发生什么?考虑以下程序。
// 文件名: Test.java public class Test { int x = 2; Test(int i) { x = i; } public static void main(String[] args) { Test t = new Test(5); System.out.println("x = " + t.x); } }
上述程序的输出是“x = 5”。Java 中使用类声明的初始化类似于C++ 中使用Initializer List 的初始化。所以,在上面的程序中,在构造函数内部赋值的值覆盖了 x 之前的值 2,x 变为 5。 作为练习,预测以下程序的输出。
// filename: Test2.java class Test1 { Test1(int x) { System.out.println("Constructor called " + x); } } // This class contains an instance of Test1 class Test2 { Test1 t1 = new Test1(10); Test2(int i) { t1 = new Test1(i); } public static void main(String[] args) { Test2 t2 = new Test2(5); } }
程序的输出是Constructor called 10 Constructor called 5。 首先在main方法中实例化t2对象。由于局部变量的初始化顺序比构造函数先,首先实例变量(t1),在类Test2中被分配到内存。在这一行中,创建了一个新的 Test1 对象,在类 Test1 中调用构造函数并打印“Constructor called 10”。接下来调用 Test2 的构造函数,并再次创建类 Test1 的新对象并打印“Constructor called 5”