父類構造方法調用被重寫的實例方法時注意的問題:
package lesson4;
class Test extends Base
{
public static void main(String[] args)
{
Test t = new Test();//在調用父類Base的構造方法時,所調用的test()爲動態調用,也即調用子類Test的test()
System.out.println("Hello World!");
}
public void test()
{
System.out.println("Test test");
}
}
class Base
{
//構造方法,引用了將來被重寫的方法
Base()
{
test();//如果實例化子類,當調用該構造方法時,調用被子類覆寫的test(),如果test()沒被覆寫,則調用Base的test()。
// 和實例方法動態調用一樣,當子類實例化時,遞歸到Base(),發現test()實例方法,現在子類中查找,沒找到的話上溯到父類……
//如果還沒找到,則拋出異常
}
public void test()
{
System.out.println("Base test!");
}
}
儘量把類中使用的輔助方法封裝起來(private)。
如果類讓使一些方法供外部使用(public),又不想有被重寫的風險,可是添加final 關鍵字,及即public final。如果某個類不想被繼承,可設置爲final類,也可以讓該類具有一個唯一的構造方法,並設置爲private訪問級別,這樣子類無法調用父類的構造方法,也就無法繼承了。
package lesson4;
class Test
{
{
System.out.println("******此時a已被系統分配了內存,儘管初始化塊在int a語句上面**********");
a = 10;
System.out.println("a初始化塊,但a不能被引用,因爲這裏在a的有效範圍之外。但可以賦值。有點不明白,吼吼\n初始化塊完畢!");
}
int a = 100;//給a賦值100;詞句含義:實例int a 和賦值並不是同步執行,而是先給a分配內存,之後系統負責執行初始化操作
//這裏a其實是第二次賦值。上邊的初始化塊先賦值。
public static void main(String[] args)
{
Test t = new Test();
System.out.println("此時a="+t.a);//此時a=100
}
public void test()
{
System.out.println("Test test");
}
}
結果:
看看總體執行順序:
package lesson4;
class Test
{
{
System.out.println("******此時啊已被系統分配了內存,儘管在初始化塊在int a語句上面**********");
a = 10;
System.out.println("a初始化塊,但a不能被引用,因爲這裏在a的有效範圍之外。但可以賦值。有點不明白,吼吼\n初始化塊完畢!");
}
int a = 100;//給a賦值100;詞句含義:實例int a 和賦值並不是同步執行,而是先給a分配內存,之後系統負責執行初始化操作
//這裏a其實是第二次賦值。上邊的初始化塊先賦值。
public static void main(String[] args)
{
Test t = new Test();
System.out.println("此時a="+t.a);//此時a=100
}
public Test()
{
System.out.println("===Test 構造方法執行===");//初始化執行完畢之後再執行構造方法
}
}
結果:
Java在加載並初始化某個類的時候,總是保證該類的所有父類(繼承樹)全部加載並初始化.。
當然前提是類加載器在加載成功後已經在運行環境中生成了該類的Class對象。