java在類的內(nèi)部創(chuàng)建本類的對(duì)象是怎么做到的?不理解啊?
問(wèn)題描述
問(wèn)題解答
回答1:先明確幾個(gè)概念,java代碼是跑在jvm中的,而jvm的內(nèi)存區(qū)域劃分為這么幾個(gè)模塊:
程序計(jì)數(shù)器(Program Counter Register):程序計(jì)數(shù)器是一個(gè)比較小的內(nèi)存區(qū)域,用于指示當(dāng)前線程所執(zhí)行的字節(jié)碼執(zhí)行到了第幾行,可以理解為是當(dāng)前線程的行號(hào)指示器。字節(jié)碼解釋器在工作時(shí),會(huì)通過(guò)改變這個(gè)計(jì)數(shù)器的值來(lái)取下一條語(yǔ)句指令。
虛擬機(jī)棧(JVM Stack):一個(gè)線程的每個(gè)方法在執(zhí)行的同時(shí),都會(huì)創(chuàng)建一個(gè)棧幀(Statck Frame),棧幀中存儲(chǔ)的有局部變量表、操作站、動(dòng)態(tài)鏈接、方法出口等,當(dāng)方法被調(diào)用時(shí),棧幀在JVM棧中入棧,當(dāng)方法執(zhí)行完成時(shí),棧幀出棧。
本地方法棧(Native Method Statck):本地方法棧在作用,運(yùn)行機(jī)制,異常類型等方面都與虛擬機(jī)棧相同,唯一的區(qū)別是:虛擬機(jī)棧是執(zhí)行Java方法的,而本地方法棧是用來(lái)執(zhí)行native方法的,在很多虛擬機(jī)中(如Sun的JDK默認(rèn)的HotSpot虛擬機(jī)),會(huì)將本地方法棧與虛擬機(jī)棧放在一起使用。
堆區(qū)(Heap):堆區(qū)是理解Java GC機(jī)制最重要的區(qū)域,沒(méi)有之一。在JVM所管理的內(nèi)存中,堆區(qū)是最大的一塊,堆區(qū)也是Java GC機(jī)制所管理的主要內(nèi)存區(qū)域,堆區(qū)由所有線程共享,在虛擬機(jī)啟動(dòng)時(shí)創(chuàng)建。堆區(qū)的存在是為了存儲(chǔ)對(duì)象實(shí)例,原則上講,所有的對(duì)象都在堆區(qū)上分配內(nèi)存(不過(guò)現(xiàn)代技術(shù)里,也不是這么絕對(duì)的,也有棧上直接分配的)。
方法區(qū)(Method Area):(也被稱為永久代),方法區(qū)是各個(gè)線程共享的區(qū)域,用于存儲(chǔ)已經(jīng)被虛擬機(jī)加載的類信息(即加載類時(shí)需要加載的信息,包括版本、field、方法、接口等信息)、final常量、靜態(tài)變量、編譯器即時(shí)編譯的代碼等。
直接內(nèi)存(Direct Memory):直接內(nèi)存并不是JVM管理的內(nèi)存,可以這樣理解,直接內(nèi)存,就是JVM以外的機(jī)器內(nèi)存,比如,你有4G的內(nèi)存,JVM占用了1G,則其余的3G就是直接內(nèi)存,JDK中有一種基于通道(Channel)和緩沖區(qū)(Buffer)的內(nèi)存分配方式,將由C語(yǔ)言實(shí)現(xiàn)的native函數(shù)庫(kù)分配在直接內(nèi)存中,用存儲(chǔ)在JVM堆中的DirectByteBuffer來(lái)引用。由于直接內(nèi)存收到本機(jī)器內(nèi)存的限制,所以也可能出現(xiàn)OutOfMemoryError的異常。
明白這幾個(gè)基本概念以后再來(lái)看看題主疑惑的地方。其實(shí)題主疑惑的是在java中,對(duì)象的引用是如何實(shí)現(xiàn)的。為什么可以在定義一個(gè)類的同時(shí),定義自己的引用,同時(shí)如果再實(shí)例化了這個(gè)引用以后,難道不會(huì)導(dǎo)致無(wú)線循環(huán)引用下去嗎?
別急我們先來(lái)分析下java中一個(gè)引用是怎么實(shí)現(xiàn)的:
一個(gè)Java的引用訪問(wèn)涉及到3個(gè)內(nèi)存區(qū)域:JVM棧,堆,方法區(qū)。
以最簡(jiǎn)單的本地變量引用:Object obj = new Object()為例:
Object obj表示一個(gè)本地引用,存儲(chǔ)在JVM棧的本地變量表中,表示一個(gè)reference類型數(shù)據(jù);
new Object()作為實(shí)例對(duì)象數(shù)據(jù)存儲(chǔ)在堆中;
堆中還記錄了Object類的類型信息(接口、方法、field、對(duì)象類型等)的地址,這些地址所執(zhí)行的數(shù)據(jù)存儲(chǔ)在方法區(qū)中;
具體的實(shí)現(xiàn)方式有很多種,句柄是其中一種,關(guān)系如圖所示。
看到這里應(yīng)該就明白了。類本身的信息,類實(shí)例數(shù)據(jù),以及指向?qū)ο蟮囊眯畔⒎謩e放在 java 的方法區(qū)和棧區(qū)以及堆區(qū)。
在題主的例子中,java加載順序是這樣的:
jvm先加載了方法區(qū)的類定義(但此時(shí)并沒(méi)有實(shí)例化這個(gè)類)
因?yàn)?public static final Direction FRONT = new Direction(); 是個(gè)靜態(tài)變量,所以這個(gè)變量也會(huì)在 jvm 第一次讀取方法區(qū)定義時(shí)被裝載進(jìn)方法區(qū)中。
同時(shí),這也意味著,在裝載這個(gè)變量的同時(shí),也在堆區(qū)實(shí)例化了這個(gè)類的實(shí)例。
注意這里面的關(guān)鍵點(diǎn),因?yàn)?FRONT 變量是靜態(tài)變量,而加載類定義只會(huì)加載一次,所以這個(gè)靜態(tài)變量也只可能加載一次。并不會(huì)像非靜態(tài)變量一樣因?yàn)檠h(huán)引用重復(fù)實(shí)例化而導(dǎo)致棧溢出。
回答2:推薦你看看R大的回答
先有Class還是先有Object?https://www.zhihu.com/questio...
回答3:說(shuō)說(shuō)你的理解,為什么類里面不能創(chuàng)建自己的對(duì)象?這幾個(gè)變量加上了static后就變成了類的屬性了,只會(huì)創(chuàng)建一次。
回答4:如果自己都不能創(chuàng)建自己,那其他類就更不能了。這樣的話這個(gè)類怎么實(shí)例化……
回答5:設(shè)計(jì)模式:?jiǎn)卫J?/p>回答6:
本質(zhì)是對(duì)java的面向?qū)ο缶幊痰牟焕斫狻?纯?3種設(shè)計(jì)模式你可能就會(huì)理解
回答7:構(gòu)造函數(shù)也是一個(gè)方法。
具有 private 訪問(wèn)權(quán)限的方法表示私有的,只有本類可見(jiàn)。
所以,本類可以調(diào)用具有 private 訪問(wèn)權(quán)限的構(gòu)造函數(shù)實(shí)例化一個(gè)對(duì)象。
回答8:使用內(nèi)部類的原因:每個(gè)內(nèi)部類都能獨(dú)立的繼承自一個(gè)(接口的)實(shí)現(xiàn),所以無(wú)論外部類是否已經(jīng)繼承了某個(gè)(接口的)的實(shí)現(xiàn),對(duì)內(nèi)部類都沒(méi)有影響。實(shí)際上內(nèi)部類有效的實(shí)現(xiàn)了“多重繼承”,就是說(shuō),內(nèi)部類允許繼承多個(gè)非接口類型。
我們知道內(nèi)部類自動(dòng)擁有對(duì)外部類所有成員的訪問(wèn)權(quán),那么這是如何做到的嗎?當(dāng)某個(gè)外部類對(duì)象創(chuàng)建了一個(gè)內(nèi)部類對(duì)象時(shí),此內(nèi)部類對(duì)象必定會(huì)秘密的捕獲一個(gè)指向那個(gè)外部類對(duì)象的引用。然后,在你訪問(wèn)外部類的成員時(shí),就是用那個(gè)引用來(lái)選擇外部類的成員。當(dāng)然這些細(xì)節(jié)是編譯器處理,并且這里的內(nèi)部類是非static的。如果一個(gè)類都不能創(chuàng)建自己的類對(duì)象,那我要你這個(gè)類何用?啊,哈哈哈哈,開(kāi)玩笑咯
相關(guān)文章:
1. mysql - 百萬(wàn)行的表中是否盡量避免使用update等sql語(yǔ)句?2. shell - Update query wrong in MySQL3. node.js - mysql如何通過(guò)knex查詢今天和七天內(nèi)的匯總數(shù)據(jù)4. Python從URL中提取域名5. mysql 插入數(shù)值到特定的列一直失敗6. python - 在使用Pycharm時(shí)經(jīng)常看到如下的樣式,小括號(hào)里紅色的部分是什么意思呢?7. javascript - 用jsonp抓取qq音樂(lè)總是說(shuō)回調(diào)函數(shù)沒(méi)有定義8. 360瀏覽器與IE瀏覽器有何區(qū)別???9. javascript - 新浪微博網(wǎng)頁(yè)版的字?jǐn)?shù)限制是怎么做的10. 怎么在網(wǎng)頁(yè)中設(shè)置圖片進(jìn)行左右滑動(dòng)
