先看一道面試題:
public class Father {
private int i=test();
private static int j=method();
static{
System.out.println("(1)");
}
Father(){
System.out.println("(2)");
}
{
System.out.println("(3)");
}
public int test(){
System.out.println("(4");
return 1;
}
public static int method(){
System.out.println("(5)");
return 1;
}
}
public class Son extends Father {
private int i=test();
private static int j=method();
static{
System.out.println("(6)");
}
Son(){
super();//寫或不寫都在,子類構造器中一定會調用父類的構造器
System.out.println("(7)");
}
{
System.out.println("(8)");
}
public int test(){
System.out.println("(9)");
return 1;
}
public static int method(){
System.out.println("(10)");
return 1;
}
public static void main(String[] args) {
Son s1=new Son();
System.out.println();
Son s2=new Son();
}
}
應該輸出多少呢?
好,欣賞完圖片放鬆後,來看下你是否答對了。。
答案:
(5)
(1)
(10)
(6)
(9)
(3)
(2)
(9)
(8)
(7)
(9)
(3)
(2)
(9)
(8)
(7)
分析:
package jobInterview.classLoadOrder;
/**
* @author zhangjinglong
* @date 2020-03-04-3:51 下午
*
* 父類的初始化<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.println("(1)");
}
Father(){
System.out.println("(2)");
}
{
System.out.println("(3)");
}
public int test(){
System.out.println("(4");
return 1;
}
public static int method(){
System.out.println("(5)");
return 1;
}
}
package jobInterview.classLoadOrder;
/**
* @author zhangjinglong
* @date 2020-03-04-3:54 下午
*
*
*
* 子類的初始化<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>執行了兩次
*/
public class Son extends Father {
private int i=test();
private static int j=method();
static{
System.out.println("(6)");
}
Son(){
super();//寫或不寫都在,子類構造器中一定會調用父類的構造器
System.out.println("(7)");
}
{
System.out.println("(8)");
}
public int test(){
System.out.println("(9)");
return 1;
}
public static int method(){
System.out.println("(10)");
return 1;
}
public static void main(String[] args) {
Son s1=new Son();
System.out.println();
Son s2=new Son();
}
}
知識點與小結
類初始化過程
1.一個類要創建實例需要先加載並初始化該類
- main方法所在的類需要先加載和初始化
2、一個子類要初始化需要先初始化父類
3、一個類初始化就是執行<clinit>
()方法
<clinit>()
方法是由靜態變量顯式賦值代碼和靜態代碼塊組成- 類變量顯式賦值代碼和靜態代碼塊代碼從上到下順序執行
<clinit>()
方法只執行一次
實例初始化過程
1、實例初始化就是執行()方法
<init>()
方法可能重載有多個,有幾個構造器就有幾個方法<init>()
方法由非靜態實例變量顯式賦值代碼和非靜態代碼塊、對應構造器代碼組成- 非靜態實例變量顯式賦值代碼和非靜態代碼塊從上到下順序執行,而對應構造器的代碼最後執行
- 每次創建實例對象,調用對應構造器,執行的就是對應的方法
<init>
方法的首行是super()
或super(實參列表)
,即對應父類的方法
方法的重寫 Override
(1)哪些方法不可以被重寫
- final 方法
- 靜態方法
- private等子類中不可見方法
(2)對象的多態性
- 子類如果重寫了父類的方法,通過子類對象調用的一定是子類重寫過的代碼
- 非靜態方法默認的調用對象是this
- this對象在構造器或者說方法中就是正在創建的對象
進階要求:
- Override和Overload的區別
- Override重寫的要求?
方法名
形參列表
返回值類型
拋出的異常列表
修飾符 - 瞭解《JVM虛擬機規範》中關於和方法的說明,invokespecial指令