一、static修飾的東東是屬于這個類的,是所有的該類的實例共享的,因此它們的初始化先于實例對象的初始化。
二、Java中沒有靜態構造方法,但是有靜態代碼塊。當類中同時存在靜態代碼塊和靜態成員變量聲明語句時,它們誰先執行?
答:按照類中定義的從上到下順序,誰在前面誰先執行。
三、當類中同時存在非靜態代碼塊和非靜態成員變量聲明語句時,它們誰先執行?
答:按照類中定義的從上到下順序,誰在前面誰先執行。
四、含有賦值的非靜態成員變量聲明語句,如 int v=4,其實這個語句的執行要分成兩步進行。首先創建對象時初始化變量v,此時v=0;然后在構造器中再給v賦值,也就是v=4。
五、非靜態初始化塊中的賦值語句、實例變量值初始化賦值語句,都比構造器中的賦值語句先執行。
原理如下:不管是非靜態初始化塊中的賦值語句,還是實例變量值初始化賦值語句,它們在編譯器處理后,都會被提取到構造器中,而且在構造器中原有的語句之前。
public class JavaTest{ //成員變量 int count=20; //非靜態初始化代碼塊 { count = 12; System.out.PRint("占個位置而已"); } //構造器 public JavaTest() { System.out.println(count); } public JavaTest(String name) { System.out.println(count); }}編譯后等價于:
public class JavaTest{ //成員變量 int count; //非靜態初始化代碼塊 { System.out.print("占個位置而已"); } //構造器 public JavaTest() { count=20;//原來的成員變量賦值 count=12;//原來的初始化代碼塊賦值 System.out.println(count); } public JavaTest(String name) { count=20;//原來的成員變量賦值 count=12;//原來的初始化代碼塊賦值 System.out.println(count); }}
六、“Java對象是由構造器創建的”這句話是錯誤的。構造器只是負責對Java對象的實例變量執行初始化而已,就像前面的三、四、五點所提及的。在執行構造器代碼之前,該實例對象所占的內存已經被分配下來了,這些內存都默認是空值——對于基本類型的變量,默認的空值就是0、0.0或者false;對于引用類型的變量,默認的控制就是Null。看看下面的代碼,分析一下結果是什么:
class base{ private int i = 2; public Base() { 這里是1處this.display(); } public void display() { System.out.println(i); }}class Derived extends base{ private int i = 22; public Derived() { i = 222; } public void display() { System.out.println(i); }}public class Test{ public static void main(String[] args) { new Derived(); }}
問題一:Derived對象的實例中有幾個”i“實例變量? 說只有一個的同學,請自己去面壁
問題二:代碼中的紅色的1處,所指的“this”是誰?是base的實例還是Derived的實例? 答案是 Derived
問題三:代碼中的紅色1處,“this.display(); ”調用的是哪個類里面的display方法? 答案是 Derived
問題四:執行Test后輸出是2?22?還是222? 答案是 0
七、編譯器在處理成員變量和方式時是有區別的。當子類和父類存在同名的成員變量時,實際是各自擁有一個名字相同的成員變量;當子類中有個方法和父類簽名相同的時候,實際是子類對父類中該方法的重寫,這個時候通過子類的實例調用這個名稱的方法將始終是子類的方法,哪怕你把子類強制轉換成父類。這么說有點迷糊,直接往下看:
class base{ private int i = 2; public Base() { this.display(); } public void display() { System.out.println("我是父類"+i); }}class Derived extends base{ private int i = 22; public Derived() { i = 222; } public void display() { System.out.println("我是子類"+i); }}
情況一:
Base b=new Base()
b.count :肯定是2,因為當前對象是父類的實例
b.display():肯定是調用父類的方法,因為當前是父類的實例
情況二:
Derived d=new Derived();
b.count: 肯定是22,因為當前對象是子類的實例,子類自己有個成員變量叫“i”干嘛拿父類的
b.display():子類的方法
情況三:
Base bd=new Derived();
b.count:肯定是2,因為當前子類是被向上轉換了,不得不拿父類的“i”
b.display():還是子類的方法,向上轉換不能太過分了,子類已經重寫的方法不能再反悔了。要想調用父類的同名方法,還得用這種方式:super.display()
情況四:
Derived d=new Derived();
Base d2b=d;
b.count:肯定是2,因為當前子類是被強制類型轉換了,不得不拿父類的“i”
b.display():還是子類的方法,強制類型轉換也不能太過分了,子類已經重寫的方法不能再反悔了。要想調用父類的同名方法,還得用這種方式:super.display()
八、從內存分配的角度來看,當程序創建一個子類對象時,JVM不僅會為該類中定義的實例變量分配內存,同時也會為其父類中定義的所有實例變量分配內存,即使子類定義了與父類中同名的實例變量。如果子類中定義了與父類同名的成員變量,那么子類中的變量會隱藏父類中定義的變量,但不是完全覆蓋,只是不能直接用而已;當把子類轉換成父類的時候或者使用”super“關鍵字,就可以使用父類中的同名成員變量了。
新聞熱點
疑難解答