類加載,類初始化及對象實例化


類的加載分為三個階段,加載--->鏈接--->初始化

 

 

類加載的過程

將class表示的二進制文件加載到內存,放在方法區中,並在堆中創建一個java.lang.Class對象(封裝的是class的數據結構)

 

類的主動使用,會加載類

 1 new Test()

 2 對類中的靜態變量進行讀寫,對接口中的靜態變量進行讀取

 3 反射某個類 , Class.forName()

 4 調用靜態方法

 5 初始化子類時,父類將被初始化

 6 啟動類  ,采用java命令執行某個類

 

 類的被動使用,不會加載類

1 子類引用父類的靜態變量 ,父類會被初始化,子類不會被初始化

public class Parent {
    public static int a = 123;

    static {
        System.out.println("Parent init");
    }
}

public class Child extends Parent {

    static {
        System.out.println("Child init");
    }
}

public class Test {
    public static void main(String[] args) {
        // 這里是訪問的父類的靜態變量
        System.out.println(Child.a);
    }
}

只初始化了父類

 

2 通過引用類型定義數組,不會觸發此類的初始化

3  final修飾的常量,不會觸發此類的初始化,因為在編譯期間就放入了常量池

4  final修飾的復雜類型,會觸發此類的初始化,因為在編譯期間不能計算得出其值

4 JVM最先初始化的總是java.lang.Object類

 

 

類初始化要注意的地方

/**
 * 
    *   在static塊里,不能對在它后面的靜態變量進行讀取的操作,但可以寫入
     *   在對它前面定義的靜態變量,可以讀取和寫入  
 */
public class MyObject {

    private static  String  x = "abc"; 
    
    static {
        
        x= "edf";
        b =12;
        //這里會提示錯誤,can not reference a field before define it 
        //System.out.println(b);
    }
    
    private static int b = 10;
}

 

/**
 * 
    *  在初始化類Foo時候,會執行類的static塊。這時候開啟兩個線程進行new對象,JVM保證了只能有一個線程執行類的初始化
 *
 */
public class ClinitTest {

    
    public static void main(String[] args) {
        new Thread(()-> {new Foo();}).start();
        new Thread(()-> {new Foo();}).start();
    }
    
}

class Foo{
    
    private static AtomicBoolean init = new AtomicBoolean(true);
    static {
        System.out.println(Thread.currentThread().getName() + " will be inint");
        while (init.get()) {

        }
        System.out.println(Thread.currentThread().getName() + "  have done inint");
    }
}

 

對象實例化

 

類的初始化和對象實例化有時是同時進行的

class Price {

    static Price P = new Price(2.7);
    static double apple = 20;
    double price;

    public Price(double orange) {
        price = apple - orange;
    }
}

public class PriceTest {
    public static void main(String[] args) {
        //Price.P訪問了類的靜態變量,會觸發類的初始化,即(加載,連接,初始化),當執行構造函數時
        //apple還沒有初始化完成,處於連接階段的准備階段,其值為默認值0,這時構造函數計算的price為-2.7
        System.out.println(Price.P.price);// 結果為-2.7
    }
}

 

class Price {
    
    
    static Price P = new Price(2.7);
    final static double apple = 20;
    double price;
    
    public Price(double orange) {
        price = apple - orange;
    }
}

public class PriceTest {
    public static void main(String[] args) {
        //apple在編譯階段就完成賦值了,其值為20,這時構造函數計算的price為17.3
        System.out.println(Price.P.price);// 結果為17.3
    }
}

 

class Price {
    
    static double apple = 20;
    static Price P = new Price(2.7);
    double price;
    
    public Price(double orange) {
        price = apple - orange;
    }
}

public class PriceTest {
    public static void main(String[] args) {
        //Price.P訪問了類的靜態變量,會觸發類的初始化,即(加載,連接,初始化),當執行構造函數時
        //apple已經完成了初始化,其值為20了,這時構造函數計算的price為17.3
        System.out.println(Price.P.price);// 結果為17.3
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM