最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中類的初始化和實(shí)例化區(qū)別詳解

 更新時(shí)間:2023年08月14日 09:33:50   作者:Marvin-Fox  
這篇文章主要介紹了Java中類的初始化和實(shí)例化區(qū)別詳解,類的初始化<BR>是完成程序執(zhí)行前的準(zhǔn)備工作,類的實(shí)例化(實(shí)例化對(duì)象)是指創(chuàng)建一個(gè)對(duì)象的過(guò)程,需要的朋友可以參考下

一、區(qū)別 

類的初始化:

是完成程序執(zhí)行前的準(zhǔn)備工作。

在這個(gè)階段,靜態(tài)的(變量,方法,代碼塊)會(huì)被執(zhí)行。同時(shí)在會(huì)開辟一塊存儲(chǔ)空間用來(lái)存放靜態(tài)的數(shù)據(jù)。

初始化只在類加載的時(shí)候執(zhí)行一次

類的實(shí)例化(實(shí)例化對(duì)象):

是指創(chuàng)建一個(gè)對(duì)象的過(guò)程。這個(gè)過(guò)程中會(huì)在堆中開辟內(nèi)存,將一些非靜態(tài)的方法,變量存放在里面。在程序執(zhí)行的過(guò)程中,可以創(chuàng)建多個(gè)對(duì)象,既多次實(shí)例化。每次實(shí)例化都會(huì)開辟一塊新的內(nèi)存。(就是調(diào)用構(gòu)造函數(shù))

在每個(gè)類初始化使用前,都會(huì)先對(duì)該類進(jìn)行加載(不是指類的實(shí)例化)

類加載有幾個(gè)步驟,加載->驗(yàn)證->準(zhǔn)備->解析->初始化

在編譯過(guò)程會(huì)把常量的值放入類的常量池中,在準(zhǔn)備過(guò)程會(huì)對(duì)類變量(static修飾的變量)賦初始值,也就是零值,同時(shí)會(huì)將常量的值賦予常量;在初始化過(guò)程會(huì)按照類文件中的聲明順序執(zhí)行類變量的賦值和靜態(tài)語(yǔ)句塊(static{}塊),如果父類還沒有初始化會(huì)先進(jìn)行父類的初始化,完成后才會(huì)進(jìn)行子類的初始化。

可以看到在初始化階段就會(huì)執(zhí)行static{}塊的語(yǔ)句,而每一個(gè)類在運(yùn)行過(guò)程中一般只會(huì)被加載一次(不是指實(shí)例化,特殊情況是使用其他類加載器對(duì)類進(jìn)行加載),所以只會(huì)完成一次初始化過(guò)程,因此也就只會(huì)執(zhí)行static{}塊一次。 類的實(shí)例化和類的加載是兩個(gè)不同的概念。

1.主要區(qū)別

2.基礎(chǔ)知識(shí)

2.1 java類的生命周期:

指一個(gè)class文件從加載到卸載的全過(guò)程,類的完整生命周期包括7個(gè)部分:加載——驗(yàn)證——準(zhǔn)備——解析——初始化——使用——卸載,如下圖所示

其中,驗(yàn)證——準(zhǔn)備——解析  稱為連接階段,除了解析外,其他階段是順序發(fā)生的,而解析可以與這些階段交叉進(jìn)行,因?yàn)镴ava支持動(dòng)態(tài)綁定(晚期綁定),需要運(yùn)行時(shí)才能確定具體類型;在使用階段實(shí)例化對(duì)象

2.2 類加載過(guò)程:

  • 加載:通過(guò)類名獲取類的二進(jìn)制字節(jié)流是通過(guò)類加載器來(lái)完成的。其加載過(guò)程使用“雙親委派模型”
  • 驗(yàn)證:當(dāng)一個(gè)類被加載之后,必須要驗(yàn)證一下這個(gè)類是否合法,比如這個(gè)類是不是符合字節(jié)碼的格式、變量與方法是不是有重復(fù)、數(shù)據(jù)類型是不是有效、繼承與實(shí)現(xiàn)是否合乎標(biāo)準(zhǔn)等等。總之,這個(gè)階段的目的就是保證加載的類是能夠被jvm所運(yùn)行。
  • 準(zhǔn)備:為類變量(靜態(tài)變量)在方法區(qū)分配內(nèi)存,并設(shè)置零值。注意:這里是類變量,不是實(shí)例變量,實(shí)例變量是對(duì)象分配到堆內(nèi)存時(shí)根據(jù)運(yùn)行時(shí)動(dòng)態(tài)生成的。
  • 解析:把常量池中的符號(hào)引用解析為直接引用:根據(jù)符號(hào)引用所作的描述,在內(nèi)存中找到符合描述的目標(biāo)并把目標(biāo)指針指針?lè)祷亍?/li>
  • 初始化:類的初始化過(guò)程是這樣的:按照順序自上而下運(yùn)行類中的變量賦值語(yǔ)句靜態(tài)語(yǔ)句,如果有父類,則首先按照順序運(yùn)行父類中的變量賦值語(yǔ)句和靜態(tài)語(yǔ)句。在類的初始化階段,只會(huì)初始化與類相關(guān)的靜態(tài)賦值語(yǔ)句和靜態(tài)語(yǔ)句,也就是有static關(guān)鍵字修飾的信息,而沒有static修飾的賦值語(yǔ)句和執(zhí)行語(yǔ)句在實(shí)例化對(duì)象的時(shí)候才會(huì)運(yùn)行。執(zhí)行<clinit>()方法(clinit是class initialize的簡(jiǎn)寫)
  • 實(shí)例化:在堆區(qū)分配內(nèi)存空間,執(zhí)行實(shí)例對(duì)象初始化,設(shè)置引用變量a指向剛分配的內(nèi)存地址

二、案例詳解

1、示例1

首先來(lái)看一個(gè)最簡(jiǎn)單的例子(無(wú)父類且無(wú)靜態(tài)成員變量)

public class OrderOfInitialization1 {
    public static void main(String[] args) {
        House house = new House();
        house.f();
    }
}
class Window {
    Window(int market) {
        System.out.println("Window(" + market + ")");
    }
}
class House {
    Window w1 = new Window(1);// before constructor
    House() {
        // show we're in constructor
        System.out.println("House()");
        w3 = new Window(33);//reinitialize w3
    }
    Window w2 = new Window(2);// after constructor
    void f() {
        System.out.println("f()");
    }
    Window w3 = new Window(3);//at end
}

output:
    Window(1)
    Window(2)
    Window(3)
    House()
    Window(33)
    f()

從輸出結(jié)果分析,House 實(shí)例變量的初始化順序是:  w1  ,  w2  ,  w3  ,然后才是構(gòu)造函數(shù)。

即:實(shí)例變量按照其在代碼中出現(xiàn)的順序執(zhí)行初始化,然后執(zhí)行構(gòu)造函數(shù)里面的初始化。

2、示例2

接下來(lái)看一個(gè)稍微復(fù)雜一些的例子(有父類但無(wú)靜態(tài)成員變量)

public class OrderOfInitialization2 {
    public static void main(String[] args) {
        SubClass subClass = new SubClass();
    }
}
class Print {
    Print(int i) {
        System.out.println("new Print(" + i + ")");
    }
}
class SuperClass {
    Print print1 = new Print(1);
    public SuperClass() {
        System.out.println("new SuperClass()");
    }
    Print print2 = new Print(2);
}
class SubClass extends SuperClass {
    Print print3 = new Print(3);
    public SubClass() {
        //這個(gè)地方其實(shí)是調(diào)用了父類的默認(rèn)的無(wú)參構(gòu)造函數(shù),super();
        //如果父類沒有無(wú)參構(gòu)造函數(shù),則這個(gè)地方必須顯式的調(diào)用父類的構(gòu)造函數(shù),否則編譯不通過(guò)
        System.out.println("new SubClass()");
    }
    Print print4 = new Print(4);
}

output:
    new Print(1)
    new Print(2)
    new SuperClass()
    new Print(3)
    new Print(4)
    new SubClass()

從輸出結(jié)果分析:這個(gè)地方是先調(diào)用了父類 SuperClass 的構(gòu)造函數(shù),然后調(diào)用子類 SubClass 的構(gòu)造函數(shù)。

即:如果一個(gè)類有父類,在實(shí)例化子類的時(shí)候,會(huì)先執(zhí)行父類的構(gòu)造函數(shù),然后執(zhí)行子類的構(gòu)造函數(shù)。

3、示例3

繼續(xù)看一個(gè)更復(fù)雜一些的例子(有父類且有靜態(tài)成員變量)

public class OrderOfInitialization3 {
    public static void main(String[] args) {
        Man man = new Man();
        Man man1 = new Man();
    }
    static Print1 print0 = new Print1(0);
}
class Print1 {
    Print1(int i) {
        System.out.println("new Print1(" + i + ")");
    }
}
class People {
    Print1 print1 = new Print1(1);
    public People() {
        System.out.println("new People()");
    }
    Print1 print2 = new Print1(2);
    static Print1 print5 = new Print1(5);
}
class Man extends People {
    Print1 print3 = new Print1(3);
    public Man() {
        System.out.println("new Man()");
    }
    Print1 print4 = new Print1(4);
    static Print1 print6 = new Print1(6);
}

output:
       new Print(0)
       new Print(5)
       new Print(6)
       new Print(1)
       new Print(2)
       new People()
       new Print(3)
       new Print(4)
       new Man()
       new Print(1)
       new Print(2)
       new People()
       new Print(3)
       new Print(4)
       new Man()

從輸出結(jié)果分析:這里首先執(zhí)行了 OrderOfInitialization3 類的靜態(tài)變量 print0 的初始化(輸出 new Print(0)),然后執(zhí)行靜態(tài)方法 main;

緊接著是執(zhí)行 People 類的靜態(tài)成員變量 print5 的初始化(輸出 new Print(5)),再接著是 Man 類的靜態(tài)成員變量 print6 的初始化(輸出 new Print(6));

之后是 People 的實(shí)例變量(輸出new Print(1)、new Print(2))、構(gòu)造函數(shù)(輸出 new People())初始化

最后才是 Man 實(shí)例變量(輸出 new Print(3)、new Print(4))、構(gòu)造函數(shù)(輸出 new Man())的初始化。

在第二次實(shí)例化一個(gè) Man 的時(shí)候,所有的靜態(tài)成員變量都沒有相應(yīng)的輸出,即靜態(tài)成員變量只初始化了一次。

所以這個(gè)地方執(zhí)行的順序是:首先執(zhí)行 main 所在類的靜態(tài)成員變量的初始化,然后是 Man 的父類的靜態(tài)成員變量的初始化,然后是子類的靜態(tài)成員的初始化;

接著是父類的構(gòu)造函數(shù),最后才是子類的構(gòu)造函數(shù)。

這個(gè)地方 Man 實(shí)例化了兩次,但是其父類和本身的靜態(tài)成員變量只初始化了一次。

為什么靜態(tài)成員變量只會(huì)初始化一次呢?

  • 實(shí)際上,靜態(tài)成員變量初始化的過(guò)程本質(zhì)上就是一個(gè)類的加載和初始化的過(guò)程,虛擬機(jī)保證了在同一個(gè)類加載器下,一個(gè)類型只會(huì)初始化一次。

4、總結(jié)一下

這個(gè)地方把類和對(duì)象分開會(huì)更好理解一點(diǎn)。

(1)類的初始化

  • 靜態(tài)成員變量初始化發(fā)生在靜態(tài)方法之前
  • 父類的初始化必須在子類初始化之前
  • 靜態(tài)成員變量的初始化順序?yàn)槠湓诖a中出現(xiàn)的順序

(2)實(shí)例化對(duì)象

  • 如果有父類,先執(zhí)行父類的實(shí)例化
  • 成員變量初始化發(fā)生在構(gòu)造函數(shù)之前
  • 成員變量的初始化順序?yàn)槠湓诖a中出現(xiàn)的順序

(3)實(shí)例化對(duì)象之前如果該類沒有初始化,必須先執(zhí)行該類的初始化。

5、最后看一個(gè)比較特殊的例子

public class NestedInitialization {
    public static void main(String[] args) {
        staticFunction();
    }
    static NestedInitialization st = new NestedInitialization();
    static {
        System.out.println("1");
    }
    {
        System.out.println("2");
    }
    NestedInitialization() {
        System.out.println("3");
        System.out.println("a=" + a + ",b=" + b);
    }
    public static void staticFunction() {
        System.out.println("4");
    }
    int a = 110;
    static int b = 112;
}

output:
    2
    3
    a=110,b=0
    1
    4

這個(gè)例子的特殊性在于,**該類還沒有完成初始化,就去實(shí)例化一個(gè)該類的對(duì)象。**我們從類的生命周期來(lái)分析,一個(gè)類會(huì)經(jīng)歷加載、驗(yàn)證、準(zhǔn)備、解析、初始化、使用和卸載七個(gè)階段,在執(zhí)行到  static NestedInitialization st = new NestedInitialization();  這一步時(shí),已經(jīng)是類的初始化階段了,此時(shí),NestedInitialization 類里面的靜態(tài)成員的值都還是準(zhǔn)備階段設(shè)置的初始零值,即  static NestedInitialization st = null , static int b = 0; ,然后這個(gè)地方需要實(shí)例化 NestedInitialization,所以是以此時(shí)的狀態(tài)去實(shí)例化 NestedInitialization 類的,執(zhí)行類的實(shí)例化,然后在繼續(xù)類的初始化。所以才會(huì)出現(xiàn)上面的輸出結(jié)果。

到此這篇關(guān)于Java中類的初始化和實(shí)例化區(qū)別詳解的文章就介紹到這了,更多相關(guān)Java初始化和實(shí)例化內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java中使用Files類的copy()方法實(shí)現(xiàn)復(fù)制文件

    Java中使用Files類的copy()方法實(shí)現(xiàn)復(fù)制文件

    這篇文章主要介紹了Java中使用Files類的copy()方法實(shí)現(xiàn)復(fù)制文件,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-05-05
  • 關(guān)于@ConfigurationProperties注解全解析

    關(guān)于@ConfigurationProperties注解全解析

    通過(guò)@ConfigurationProperties和@ConditionalOnProperty注解,可以實(shí)現(xiàn)基于配置的條件加載Bean,以此優(yōu)化Spring Boot應(yīng)用的啟動(dòng)速度,在application.yml中設(shè)置配置項(xiàng),如是否加載特定的Bean(以swagger配置為例)
    2024-11-11
  • springboot @Value實(shí)現(xiàn)獲取計(jì)算機(jī)中絕對(duì)路徑文件的內(nèi)容

    springboot @Value實(shí)現(xiàn)獲取計(jì)算機(jī)中絕對(duì)路徑文件的內(nèi)容

    這篇文章主要介紹了springboot @Value實(shí)現(xiàn)獲取計(jì)算機(jī)中絕對(duì)路徑文件的內(nèi)容,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2021-09-09
  • Spring配置動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)讀寫分離的方法

    Spring配置動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)讀寫分離的方法

    這篇文章主要介紹了利用Spring配置動(dòng)態(tài)數(shù)據(jù)源實(shí)現(xiàn)讀寫分離的方法,文中通過(guò)示例代碼介紹的很詳細(xì),相信對(duì)大家的理解和學(xué)習(xí)具有一定的參考借鑒價(jià)值,藕需要的朋友可以一起學(xué)習(xí)學(xué)習(xí)。
    2017-01-01
  • SpringBoot實(shí)現(xiàn)整合微信支付方法詳解

    SpringBoot實(shí)現(xiàn)整合微信支付方法詳解

    這篇文章主要介紹了SpringBoot實(shí)現(xiàn)整合微信支付的過(guò)程詳解,文中的示例代碼對(duì)我們的工作或?qū)W習(xí)有一定的幫助,感興趣的小伙伴可以跟隨小編學(xué)習(xí)一下
    2021-12-12
  • java null轉(zhuǎn)換為字符串的三種方法

    java null轉(zhuǎn)換為字符串的三種方法

    在Java開發(fā)中,正確處理null值至關(guān)重要,以避免空指針異常,本文介紹了三種常見的null值轉(zhuǎn)字符串方法:三元運(yùn)算符、Objects.toString方法、String.valueOf方法,感興趣的可以了解一下
    2024-10-10
  • Spring中@Validated和@Valid區(qū)別淺析

    Spring中@Validated和@Valid區(qū)別淺析

    @Valid是javax.validation里的,?@Validated是@Valid?的一次封裝,是Spring提供的校驗(yàn)機(jī)制使用,下面這篇文章主要給大家介紹了關(guān)于Spring中@Validated和@Valid區(qū)別的相關(guān)資料,需要的朋友可以參考下
    2022-04-04
  • Java日志框架打印應(yīng)用程序日志代碼的執(zhí)行情況分析

    Java日志框架打印應(yīng)用程序日志代碼的執(zhí)行情況分析

    在配置INFO日志級(jí)別時(shí),日志器(logger)中debug級(jí)的日志代碼仍會(huì)被執(zhí)行,只是是否輸出取決于配置的日志級(jí)別,本文基于Java 1.8、SLF4J 1.7.25和Log4j 2.20.0進(jìn)行實(shí)驗(yàn),詳述了日志框架處理日志代碼的機(jī)制,感興趣的朋友一起看看吧
    2024-10-10
  • SpringSecurity認(rèn)證授權(quán)全流程解讀

    SpringSecurity認(rèn)證授權(quán)全流程解讀

    這篇文章主要介紹了SpringSecurity認(rèn)證授權(quán)全流程,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2025-06-06
  • SpringBoot中的CSRF攻擊及預(yù)防方法

    SpringBoot中的CSRF攻擊及預(yù)防方法

    CSRF攻擊是一種常見的網(wǎng)絡(luò)攻擊方式,可以通過(guò)欺騙用戶來(lái)執(zhí)行惡意操作,在Spring Boot應(yīng)用程序中,我們可以采取多種措施來(lái)預(yù)防CSRF攻擊,本文將給大家介紹一下CSRF攻擊以及如何預(yù)防攻擊,需要的朋友可以參考下
    2023-07-07

最新評(píng)論

湾仔区| 永丰县| 长岭县| 象州县| 绥德县| 平果县| 潞西市| 乌拉特前旗| 广平县| 三原县| 蒙山县| 苗栗市| 新邵县| 贡嘎县| 沈阳市| 盘山县| 澄迈县| 淳化县| 奈曼旗| 米泉市| 永清县| 察哈| 三河市| 饶阳县| 山丹县| 勃利县| 湘潭市| 永兴县| 准格尔旗| 山西省| 乐都县| 大关县| 达州市| 通河县| 府谷县| 嫩江县| 江安县| 东乌珠穆沁旗| 荥经县| 泽库县| 崇明县|