日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java类和对象初始化

發(fā)布時間:2023/12/19 java 35 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java类和对象初始化 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

首先對Java 較為深層技術(shù)提幾個問題(包含class 文件格式的了解):

1.類的訪問權(quán)限在class二進(jìn)制文件中怎么體現(xiàn)的? 2.類中static 區(qū)域 怎么初始化的,時間,順序,特點是什么? 3.jvm pc 程序計數(shù)器(寄存器) 會不會出現(xiàn)OOM問題? 4.類中成員方法和成員變量有沒有最大個數(shù)限制? 5.類裝載是一次性全加載的嗎,還是動態(tài)的? 6.jvm 本地方法棧是什么? 7.類對象是什么,什么時候被創(chuàng)建的?和加載器有什么關(guān)系? 8.不同多個classloader ?在管理方法區(qū)上是怎么劃分的?不同的classloader可以在同一個jvm上加載同一個類嗎? 9.jvm 為每一個線程在堆上面配置一個緩存空間嗎?這個空間可以使用jvm配置嗎? 10.jvm 會為每一個線程配一個程序計數(shù)器嗎?

類的生命周期:

在Jvm內(nèi)存管理上有一個很重要的內(nèi)存區(qū)--運(yùn)行時常量池。其中保存類加載后的符號引用,常量,字面量等信息。在常見對象的時候,首先要到這個常量池中尋找對應(yīng)類的符號引用,才能判斷這個類是否已經(jīng)加載了。

創(chuàng)建對象的流程:

到運(yùn)行池尋找對應(yīng)類的符號引用,如果沒有,那么就加載類,類在加載的時候就會在方法區(qū)創(chuàng)建類對象數(shù)據(jù),其是一切類數(shù)據(jù)(包含方法)被訪問的數(shù)據(jù)入口(類對象)。創(chuàng)建的類對象和加載此類的類加載器也是相關(guān)的,因為不同類加載器在方法區(qū)有自己不同的命名空間,那么創(chuàng)建的類數(shù)據(jù)入口也是有空間區(qū)分的,那么在運(yùn)行池中的符號引用也是包含類加載信息的。所以在方法區(qū)中加載類就是聲明類數(shù)據(jù)入口,也就是傳統(tǒng)所說的類對象。

接著才是驗證字節(jié)碼的正確性,安全性,準(zhǔn)備階段主要是在方法區(qū)分配類數(shù)據(jù)空間。解析就是在空間上創(chuàng)建引用,變量等。初始化是clinit方法完成的,對類成員進(jìn)行數(shù)據(jù)初始化賦值。

Java類的初始化:

本階段負(fù)責(zé)為類變量賦正確的初始值。(類變量即靜態(tài)變量)

Java編譯器把所有的類變量初始化語句和靜態(tài)初始化器通通收集到<clinit>方法中,該方法只能被JVM調(diào)用,專門承擔(dān)初始化工作。

初始化一個類必須保證其直接超類已被初始化。

并非所有類都擁有<clinit>()方法。以下類不會擁有<clinit>方法:

  • 該類既沒有聲明任何類變量,也沒有靜態(tài)初始化語句。
  • 該類聲明了類變量,但沒有使用類變量初始化語句或靜態(tài)初始化語句初始化。 ??初始化語句是開發(fā)人員的賦值語句,和默認(rèn)值沒有關(guān)系。對于存在類成員變量如static,對于static是類變量,那么在類加載的時候,就有分配空間,并賦予初始值,int 默認(rèn)是0,doubles是0.0,long 是0,引用類型全是空;但是這和初始化是兩碼事。對于其他成員變量,只有clinit調(diào)用的時候,才會分配空間,并進(jìn)行初始化。當(dāng)然此時static也會初始化。
  • 該類只包含靜態(tài)final變量的類變量初始化語句,并且類變量初始化語句是常量表達(dá)式。 ?為什么 static final int a = 1; 定義常量不用調(diào)用clinit呢? 常量又是怎么初始化的?
  • Java類初始化的時機(jī):

    規(guī)范定義類的初始化時機(jī)為“initialize on first active use”,即“在首次主動使用時初始化”。裝載和鏈接在初始化之前就要完成。

    首次主動使用的情形:

  • 創(chuàng)建類的新實例--new,反射,克隆或反序列化;
  • 調(diào)用類的靜態(tài)方法;
  • 操作類和接口的靜態(tài)字段;(final字段除外)
  • 調(diào)用Java的特定的反射方法;
  • 初始化一個類的子類;
  • 指定一個類作為Java虛擬機(jī)啟動時的初始化類(含有main方法的啟動類)。
  • 除了以上6種情形,java中類的其他使用方式都是被動使用,不會導(dǎo)致類的初始化。

    注意:類對象的初始化clinit調(diào)用不是加載器自我觸發(fā)的,而是被動調(diào)用的時候初始化的!!!!!如果沒有任何的類成員變量,或者成員初始化語句,那么也就沒有clinit調(diào)用,那么也就沒有類對象。類被加載后,會在字符常量池中創(chuàng)建類信息,那么創(chuàng)建對象的時候,首先要到字符常量池中尋找確認(rèn)有沒有這個類已經(jīng)被加載了,否在類加載器需要去加載該類。

    Class對象 -- 訪問一切類數(shù)據(jù)(包含方法)的入口

    類型信息在運(yùn)行時如何表示(RTTI),由Class對象的特殊對象完成,Class對象包含與類有關(guān)的信息。
    類作為程序中的一部分,每個類都有一個Class對象(即,每當(dāng)編寫且編譯了一個新類,就會產(chǎn)生一個Class對象,這個對象被保存在一個同名的.class文件中,Class對象也是類的唯一標(biāo)識(如果你了解class二進(jìn)制文件格式,那么在utf-8字符常量池中包含類信息)

    Class 沒有公共構(gòu)造方法。Class 對象是在加載類時由 Java 虛擬機(jī)以及通過調(diào)用類加載器中的 defineClass 方法自動構(gòu)造的,因此不能顯式地聲明一個Class對象。?

    虛擬機(jī)為每種類型管理一個獨一無二的Class對象。也就是說,每個類(型)都有一個Class對象。運(yùn)行程序時,Java虛擬機(jī)(JVM)首先檢查是否所要加載的類對應(yīng)的Class對象(被映射存儲在常量池中)是否已經(jīng)加載。如果沒有加載,JVM就會根據(jù)類名查找.class文件,并將其Class對象載入。一般某個類的Class對象被載入內(nèi)存,它就用來創(chuàng)建這個類的所有對象。

    Java對象初始化:

    編譯器為每個類生成至少一個實例初始化方法,即<init>()方法。此方法與源程序里的每個構(gòu)造方法對應(yīng)。如果類沒有聲明構(gòu)造方法,則生成一個默認(rèn)構(gòu)造方法,該方法僅調(diào)用父類的默認(rèn)構(gòu)造方法,同時生成與該默認(rèn)構(gòu)造方法對應(yīng)的<init>()方法。

    <init>()方法內(nèi)容大概為:

  • 調(diào)用另一個<init>()方法(本類的另外一個<init>()方法或父類的<init>()方法);
  • 初始化實例變量;
  • 與其對應(yīng)的構(gòu)造方法內(nèi)的字節(jié)碼
  • Java對象初始化的時機(jī):

    對象初始化又稱為對象實例化。Java對象在其被創(chuàng)建時初始化。有兩種方式創(chuàng)建Java對象:

    一種是顯示對象創(chuàng)建,通過new關(guān)鍵字來調(diào)用一個類的構(gòu)造函數(shù),通過構(gòu)造函數(shù)創(chuàng)建一個對象。

    一種是隱式對象創(chuàng)建:

  • 加載一個包含String字面量的類或接口會引起一個新的String對象創(chuàng)建,除非包含相同字面量的String對象已經(jīng)在JVM中存在了。 String s1 = "zheng";

    ?

  • 自動裝箱機(jī)制可能會引起一個原子類型的包裝類對象被創(chuàng)建。 Integer iWrapper = 1;

    ?

  • String連接符也可能會引起新的String或者StringBuilder對象被創(chuàng)建,同時還有可能引起原子類型的包裝對象被創(chuàng)建。 System.out.println("zheng"+1);
  • 對象實例初始化的例子:

    public class Base {Base() {preProcess();}void preProcess() {} } public class Derived extends Base {public String whenAmISet = "set when declared";@Override void preProcess(){whenAmISet = "set in preProcess()";} } public class Main {public static void main(String[] args){Derived d = new Derived();System.out.println( d.whenAmISet );} }

    下面是整個的運(yùn)行流程:

  • 進(jìn)入Derived類構(gòu)造函數(shù)
  • Derived成員變量的內(nèi)存被分配
  • 調(diào)用Base類的構(gòu)造函數(shù)
  • Base類構(gòu)造函數(shù)調(diào)用preProcess()方法
  • Derived類的preProcess()方法設(shè)置whenAmISet
  • Derived類的成員變量初始化被調(diào)用
  • 執(zhí)行Derived構(gòu)造函數(shù)體
  • 可以看到在執(zhí)行完父類的構(gòu)造函數(shù)后,第6步才對Derived類的成員變量初始化。

    Java類初始化例子:

    import java.util.Map; import java.util.HashMap; import java.util.Collections; public class Singleton {public static Singleton singleton = new Singleton();public static Map m;static{m = new HashMap(); }private Singleton(){initM();}public static void initM(){if(null == m){System.out.println("m 為空");m = new HashMap();}m.put("1", "鄭");m.put("2", "陳");}public static Singleton getInstance(){return singleton;} } public class Main {public static void main(String [] args){Singleton singleton = Singleton.getInstance();} }

    運(yùn)行結(jié)果輸出m 為空

    是因為在類初始化階段先對singleton賦值調(diào)用Singleton類構(gòu)造函數(shù),然后Singleton類構(gòu)造函數(shù)調(diào)用initM()方法。但是此時還沒有運(yùn)行static方法,所以m=null.

    總結(jié)

    以上是生活随笔為你收集整理的Java类和对象初始化的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。