考點:
對類初始化(<clinit>()),類實例化(<init>())和方法重寫(override)的理解。
題目:
main方法的輸出結果是什麼?
/*
* 父類的初始化<clinit>:
* (1)j = method();
* (2)父類的靜態代碼塊
*
* 父類的實例化方法:
* (1)super()(最前)
* (2)i = test();
* (3)父類的非靜態代碼塊
* (4)父類的無參構造(最後)
*
* 非靜態方法前面其實有一個默認的對象this
* this在構造器(或<init>)它表示的是正在創建的對象,因爲這裏是在創建Son對象,所以
* test()執行的是子類重寫的代碼(面向對象多態)
*
* 這裏i=test()執行的是子類重寫的test()方法
*/
public class Father{
private int i = test();
private static int j = method();
static{
System.out.print("(1)");
}
Father(){
System.out.print("(2)");
}
{
System.out.print("(3)");
}
public int test(){
System.out.print("(4)");
return 1;
}
public static int method(){
System.out.print("(5)");
return 1;
}
}
/*
* 子類的初始化<clinit>:
* (1)j = method();
* (2)子類的靜態代碼塊
*
* 先初始化父類:(5)(1)
* 初始化子類:(10)(6)
*
* 子類的實例化方法<init>:
* (1)super()(最前) (9)(3)(2)
* (2)i = test(); (9)
* (3)子類的非靜態代碼塊 (8)
* (4)子類的無參構造(最後) (7)
*
* 因爲創建了兩個Son對象,因此實例化方法<init>執行兩次
*
* (9)(3)(2)(9)(8)(7)
*/
public class Son extends Father{
private int i = test();
private static int j = method();
static{
System.out.print("(6)");
}
Son(){
// super();//寫或不寫都在,在子類構造器中一定會調用父類的構造器
System.out.print("(7)");
}
{
System.out.print("(8)");
}
public int test(){
System.out.print("(9)");
return 1;
}
public static int method(){
System.out.print("(10)");
return 1;
}
public static void main(String[] args) {
Son s1 = new Son();
System.out.println("---");
Son s2 = new Son();
}
}
分析:
一個類要創建實例,首先要加載和初始化該類:
1、main方法所在的類需要先加載和初始化
2、子類初始化之前要先執行父類,一個類的初始化就是<clinit>()方法()
3、初始化的內容:static靜態,按順序初始化即(5)(1)(10)(6)
下一步就是創建實例,創建實例需要對實例初始化:
前方高能預警------->
1、實例初始化就是執行<init>()方法。
2、<init>()方法可能有多個,有幾個構造器就有幾個<init>()方法。
3、<init>()方法由(1)非靜態實例變量,(2)非靜態代碼塊,(3)對應構造器代碼組成。
4、<init>()方法的首行是super(),即對應父類的<init>()方法。
5、super一定第一個執行,對應構造器一定最後執行,其它兩個按照代碼的順序執行。
根據上面的步驟,先執行的是super(),也就是對應父類的<init>
先執行父類的super,沒有輸出
然後執行父類的private int i = test();
按理說改輸出(4)的,但是子類對test()這個方法重寫了,
所以需要執行的test()方法是子類的test方法,而非父類的test()方法。
所以輸出了(9)
然後執行父類的{
System.out.print("(3)");
}
輸出(3)
最後是父類的構造器
Father(){
System.out.print("(2)");
}
輸出(2)
至此,父類的<init>()方法執行完了,也就是子類的super()執行完了。
然後該執行子類的private int i = test();
輸出(9)
然後執行子類的{
System.out.print("(8)");
}
輸出(8)
最後執行子類的無參構造
Son(){
System.out.print("(7)");
}
輸出(7)
最終的結果是:(5)(1)(10)(6)(9)(3)(2)(9)(8)(7)---(9)(3)(2)(9)(8)(7)
如果對上述的分析還是不理解,就再做一題!
public class Father{
private static int j = method();
static{
System.out.print("(1)");
}
Father(){
System.out.print("(2)");
}
{
System.out.print("(3)");
}
private int i = test();
public int test(){
System.out.print("(4)");
return 1;
}
public static int method(){
System.out.print("(5)");
return 1;
}
}
public class Son extends Father{
private int i = test();
private static int j = method();
static{
System.out.print("(6)");
}
Son(){
System.out.print("(7)");
}
{
System.out.print("(8)");
}
public int test(){
System.out.print("(9)");
return 1;
}
public static int method(){
System.out.print("(10)");
return 1;
}
public static void main(String[] args) {
Son s1 = new Son();
System.out.println("---");
Son s2 = new Son();
}
}
答案是:(5)(1)(10)(6)(3)(9)(2)(9)(8)(7)---(3)(9)(2)(9)(8)(7)
你會發現(9)(3)換了位置,這就是之前所說的順序問題:
5、super一定第一個執行,對應構造器一定最後執行,其它兩個按照代碼的順序執行。
針對方法的重寫Override
哪些方法不能被重寫?
1、final
2、private
3、靜態方法
哪些方法能被重寫?
除了上述的情況,剩下的都能被重寫!