欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

一、區(qū)別 

類(lèi)的初始化:

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

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

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

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

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

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

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

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

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

1.主要區(qū)別

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

2.1 java類(lèi)的生命周期:

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

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

2.2 類(lèi)加載過(guò)程:

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

二、案例詳解

1、示例1

首先來(lái)看一個(gè)最簡(jiǎn)單的例子(無(wú)父類(lèi)且無(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ù)雜一些的例子(有父類(lèi)但無(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)用了父類(lèi)的默認(rèn)的無(wú)參構(gòu)造函數(shù),super();
        //如果父類(lèi)沒(méi)有無(wú)參構(gòu)造函數(shù),則這個(gè)地方必須顯式的調(diào)用父類(lèi)的構(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)用了父類(lèi) SuperClass 的構(gòu)造函數(shù),然后調(diào)用子類(lèi) SubClass 的構(gòu)造函數(shù)。

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

3、示例3

繼續(xù)看一個(gè)更復(fù)雜一些的例子(有父類(lèi)且有靜態(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 類(lèi)的靜態(tài)變量 print0 的初始化(輸出 new Print(0)),然后執(zhí)行靜態(tài)方法 main;

緊接著是執(zhí)行 People 類(lèi)的靜態(tài)成員變量 print5 的初始化(輸出 new Print(5)),再接著是 Man 類(lèi)的靜態(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)成員變量都沒(méi)有相應(yīng)的輸出,即靜態(tài)成員變量只初始化了一次。

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

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

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

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

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

4、總結(jié)一下

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

(1)類(lèi)的初始化

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

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

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

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

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

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

相關(guān)文章

  • Java在Excel中創(chuàng)建多級(jí)分組、折疊或展開(kāi)分組的實(shí)現(xiàn)

    Java在Excel中創(chuàng)建多級(jí)分組、折疊或展開(kāi)分組的實(shí)現(xiàn)

    這篇文章主要介紹了Java在Excel中創(chuàng)建多級(jí)分組、折疊或展開(kāi)分組的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-05-05
  • 詳解Spring中接口的bean是如何注入的

    詳解Spring中接口的bean是如何注入的

    這篇文章主要介紹了詳解Spring中接口的bean是如何注入的的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • java實(shí)現(xiàn)讀取txt文件中的內(nèi)容

    java實(shí)現(xiàn)讀取txt文件中的內(nèi)容

    本文通過(guò)一個(gè)具體的例子向大家展示了如何使用java實(shí)現(xiàn)讀取TXT文件里的內(nèi)容的方法以及思路,有需要的小伙伴可以參考下
    2016-03-03
  • Jenkins之Log Parse使用方法詳解

    Jenkins之Log Parse使用方法詳解

    這篇文章主要為大家詳細(xì)介紹了Jenkins插件Log Parse使用方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-08-08
  • java常量字符串過(guò)長(zhǎng)報(bào)錯(cuò)的解決辦法以及原因分析

    java常量字符串過(guò)長(zhǎng)報(bào)錯(cuò)的解決辦法以及原因分析

    在IDEA中字符串長(zhǎng)度超過(guò)65535,進(jìn)行打印,IDEA會(huì)提示java:常量字符串過(guò)長(zhǎng),這篇文章主要給大家介紹了關(guān)于java常量字符串過(guò)長(zhǎng)報(bào)錯(cuò)的解決辦法以及原因分析,需要的朋友可以參考下
    2023-01-01
  • java普通類(lèi)如何轉(zhuǎn)javafx程序

    java普通類(lèi)如何轉(zhuǎn)javafx程序

    這篇文章主要介紹了java普通類(lèi)如何轉(zhuǎn)javafx程序方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • Java編程實(shí)現(xiàn)軌跡壓縮算法開(kāi)放窗口實(shí)例代碼

    Java編程實(shí)現(xiàn)軌跡壓縮算法開(kāi)放窗口實(shí)例代碼

    這篇文章主要介紹了Java編程實(shí)現(xiàn)軌跡壓縮算法開(kāi)放窗口實(shí)例代碼,具有一定借鑒價(jià)值,需要的朋友可以參考下。
    2017-11-11
  • SpringBoot整合Spring Batch示例代碼

    SpringBoot整合Spring Batch示例代碼

    這篇文章主要來(lái)和大家一起探討一下SpringBoot如何整合Spring Batch,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2023-10-10
  • 基于指針pointers和引用references的區(qū)別分析

    基于指針pointers和引用references的區(qū)別分析

    本篇文章介紹了,基于指針pointers和引用references的區(qū)別分析。需要的朋友參考下
    2013-05-05
  • IDEA2020.1構(gòu)建Spring5.2.x源碼的方法

    IDEA2020.1構(gòu)建Spring5.2.x源碼的方法

    這篇文章主要介紹了IDEA2020.1構(gòu)建Spring5.2.x源碼的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-10-10

最新評(píng)論