[英]Initialization of final fields
有人可以向我解釋此示例的行為:
package test;
public class Test {
static abstract class Parent{
public Parent() {
print();
}
public abstract void print();
}
static class Child extends Parent{
protected final int i= 10;
public Child() {
super();
}
public void print(){
System.out.println(i);
}
}
public static void main(String[] args) {
System.out.println("Test");
new Child();
}
}
此代碼段的輸出為10 。 但是,當我將變量i更改為任何對象(例如Integer)時,輸出為null 。 但是,當我改變我的靜態整數輸出為10預期。
我認為,在調用任何方法(或構造函數)之前都要先初始化字段,但是這里這種方法僅適用於原始類型,而不適用於對象。
謝謝
拉迪姆
類的實例字段是在構造函數中的super()
調用之后直接初始化的,無論它們是否為最終值。 但是, super()
調用父級的類構造函數,該構造函數讀取因此未初始化的字段的值。
上課的時候在運行時,這意味着一類的構造函數被調用(在之前之前靜態字段initilized引用類的靜態字段都被初始化super()
在類的構造函數調用)。
當字段類型為int時,為什么仍打印10的原因是,Java編譯器可以在編譯時內聯最后字段的值。 在那種情況下,程序永遠不會讀取該字段的值,因為編譯器優化了代碼,使其看起來像System.out.println(10)
而不是System.out.println(i)
。 在這種情況下,Java編譯器不會內聯最后字段,但是,對於原始字段類型很可能這樣做,而對於大多數對象類型則不太可能。
非靜態成員:
new Child()
以此順序觸發構造函數鏈接Parent()-> Child()。
當父對象被實例化時,您正在調用print(),因為它持有子對象的引用,它將調用
public void print(){
System.out.println(i);
}
因為在這個階段,孩子的啟蒙還沒有完成。 整數i
沒有任何值,因此它將輸出null
。
靜態變量:
一旦引用/調用了相應的類, Static data member
被初始化,因此它將打印10
。
這是因為邏輯上,應該在Child
存在之前Parent
應該存在。
因此,首先調用Parent
的構造函數,在此期間, 不會初始化Child
任何字段。
因此,當您調用被 Child
覆蓋的print()
時,將print()
i
的未初始化值。
在類加載期間發生的類初始化時進行初始化,因此它們將具有初始化的值
由於字段的最終性質,與變量不同,它在構造函數之前初始化。 因此,將打印該值。
當您聲明final Integer i = 10
時會發生什么? 或者int i = 10
?
主代碼應為
Child child = new Child();
child.print();
然后,如果使用int或Integer,則返回10;否則,返回10。
僅使用
new Child()
則此變量沒有返回值,並且新實例被忽略。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.