JAVA類加載及初始化過程面試題

先看一道面試題:

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指令
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章