Java 靜態、類加載


1.靜態是什么?有什么用?

static的主要作用在於創建獨立於具體對象的域變量或者方法。

每創建一個對象,都會在堆里開辟內存,存成員(屬性),但是不存方法,方法是共用的,沒必要每一個對象都浪費內存去存方法。有一個叫方法區的地方,專門存方法。方法區里又有靜態域,存靜態變量或者靜態方法。

普通變量和方法的調用:通過對象調用

靜態變量和方法的調用:通過對象或類調用

public class MyTest8 {
    public static void main(String[] args) {
        System.out.println(Plant.name);//通過類調用
        Plant p1=new Plant();
        System.out.println(p1.name);//通過對象調用
        p1.name="植物";//類似方法,是公用的,改了之后就是改了,新建對象也是這個值
        Plant p2=new Plant();
        System.out.println(p2.name);//通過對象調用
    }
}

class Plant{
    static String name="靜態植物";
    public static void say() {
        System.out.println("植物類");
    }
}
/**輸出
靜態植物
靜態植物
植物
*/
靜態的調用

 在類被加載的時候,靜態的代碼都會被加載,並且只加載一次,放在方法區里,該類的對象一起用。省時省力。

 

2.加載類有什么用?

任何程序都要先加載到內存中才能和CPU進行交流,而JVM中的ClassLoader(類加載器)就是負責提前將,class文件加載到內存中去的。

 

3.類何時被加載?(普通人的宏觀理解)

  • 實例化對象時,如Chinese c1=new Chinese();此時加載了Chinese類
  • 通過類名調用靜態變量或靜態方法的時候
  • 如果實例化子類對象,會先加載父類

通過代碼驗證:

public class MyTest8 {

    public static void main(String[] args) {
        Plant.say();//通過類名調用靜態方法
        Plant p1 = new Plant();//創建對象
        Plant p2 = new Plant();
    }
}

class Plant{
    static String name="靜態植物";
    public static void say() {
        System.out.println("植物類");
    }
    static {
        System.out.println("植物類的靜態代碼被執行加載了");
    }
    {
        System.out.println("植物類的普通代碼被加載了");
    }
}

輸出:

植物類的靜態代碼被執行加載了
植物類
植物類的普通代碼被加載了
植物類的普通代碼被加載了

由此可知,Plant.say();調用方法時就加載了類,靜態代碼也都被執行了,並且只執行一次,創建對象的時候再次加載類,但是不執行靜態代碼,而是非靜態代碼。

 

再通過繼承關系觀察靜態和非靜態的關系

public class MyTest8 {

    public static void main(String[] args) {
        Flower.say();//通過類名調用靜態方法
        Flower f1=new Flower();//創建花類對象
        Flower f2=new Flower();
    }
}

class Plant{
    static String name="靜態植物";
    public static void say() {
        System.out.println("植物類");
    }
    static {
        System.out.println("植物類的靜態代碼被執行加載了");
    }
    {
        System.out.println("植物類的普通代碼被加載了");
    }
}

class Flower extends Plant{
    static {
        System.out.println("花類被加載了");
    }
    
    static String name="花";
    public static void say() {
        System.out.println("花類");
    }
    {
        System.out.println("花類的普通代碼被加載了");
    }
}

輸出:

植物類的靜態代碼被執行加載了
花類被加載了
花類
植物類的普通代碼被加載了
花類的普通代碼被加載了
植物類的普通代碼被加載了
花類的普通代碼被加載了

由此可知:調用靜態的東西,只執行靜態的代碼,靜態代碼只執行一次。創建對象的時候也會加載,如果靜態沒有被加載過也會被加載,加載過就不用。加載子類的時候,會先把父類加載一次。

在代碼中,調用子類靜態方法,則先加載父類的靜態代碼,再加載子類的靜態代碼,再調用方法。創建對象的時候,先加載父類,再加載子類。

類裝載的過程:

  • 加載:根據查找路徑找到相應的 class 文件然后導入;
  • 檢查:檢查加載的 class 文件的正確性;
  • 准備:給類中的靜態變量分配內存空間;
  • 解析:虛擬機將常量池中的符號引用替換成直接引用的過程。符號引用就理解為一個標示,而在直接引用直接指向內存中的地址;
  • 初始化:對靜態變量和靜態代碼塊執行初始化工作。

 


牛客刷題

1.初始化代碼執行順序是:父類靜態→子類靜態→父類普通代碼塊→子類普通代碼塊→父類構造方法→子類構造方法

2.靜態方法屬於類不屬於對象;靜態方法中只能訪問其他靜態方法和靜態數據,不能訪問非靜態的。

3.靜態不可用this調用。


免責聲明!

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



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