簡(jiǎn)單了解java類(lèi)的初始化以及類(lèi)的實(shí)例化
前言
上一篇我們知道了一個(gè)類(lèi)的生命周期是:加載->驗(yàn)證->準(zhǔn)備->解析->初始化->使用->卸載。
當(dāng)初始化完成以后,一個(gè)類(lèi)所有的類(lèi)變量(被static修飾的變量)都被賦值。但是未被static修飾的成員變量又是何時(shí)被賦值的呢?
一個(gè)類(lèi)何時(shí)會(huì)被初始化
一個(gè)類(lèi)何時(shí)被初始化可以分為以下幾類(lèi):
- 1.創(chuàng)建類(lèi)的實(shí)例(new)。
- 2.訪問(wèn)某個(gè)類(lèi)或接口的靜態(tài)變量,或者對(duì)該靜態(tài)變量賦值。
- 3.調(diào)用類(lèi)的靜態(tài)方法。
- 4.通過(guò)反射方式執(zhí)行以上三種行為。
- 5.初始化子類(lèi)的時(shí)候,會(huì)觸發(fā)父類(lèi)的初始化。
- 6.Java虛擬機(jī)啟動(dòng)時(shí)被標(biāo)明為啟動(dòng)類(lèi)的類(lèi)。(有main方法的類(lèi))
- 7.JDK 1.7開(kāi)始提供的動(dòng)態(tài)語(yǔ)言支持。(了解即可)
我們來(lái)說(shuō)道說(shuō)道第3點(diǎn)和第6點(diǎn)
我們平常在使用main方法和調(diào)用某個(gè)類(lèi)的靜態(tài)方法的時(shí)候,是不是發(fā)現(xiàn),并不能直接調(diào)用靜態(tài)方法和main方法所在類(lèi)的非靜態(tài)方法和非靜態(tài)變量。
可是明明不是說(shuō)了在調(diào)用靜態(tài)方法和執(zhí)行main方法的時(shí)候,所在的類(lèi)已經(jīng)被初始化了嗎?
是的!在上一章節(jié)我們就說(shuō),類(lèi)初始化的時(shí)候會(huì)按照我們編寫(xiě)代碼的順序?yàn)轭?lèi)變量(static修飾的變量)進(jìn)行賦值。注意哦,此時(shí)這個(gè)類(lèi)僅僅只有靜態(tài)變量被正確賦值了哦。
public class People{ private static String name ="lisi"; private int age = 18; static{ name ="zhangsan"; } }
如上述代碼,在該類(lèi)被初始化之后,首先按照代碼順序?qū)㈩?lèi)變量(被static修飾的變量)賦值。所以name被賦值"lishi",然后再將name賦值為 "zhangsan"。此時(shí)age并沒(méi)有值,直接直接調(diào)用會(huì)報(bào)錯(cuò)。
一個(gè)類(lèi)何時(shí)被實(shí)例化
上一個(gè)章節(jié)中,我們明白了加載->驗(yàn)證->準(zhǔn)備->解析->初始化的具體細(xì)節(jié)。
當(dāng)初始化完成后,一個(gè)類(lèi)的靜態(tài)變量被正確賦值。如果這個(gè)對(duì)象是被new出來(lái)的。那么在初始化完成之后會(huì)進(jìn)入實(shí)例化階段。
實(shí)例化的具體步驟為:
父類(lèi)非靜態(tài)成員初始化語(yǔ)句(包括代碼塊,按照在類(lèi)定義中的順序執(zhí)行)->父類(lèi)構(gòu)造函數(shù)->子類(lèi)非靜態(tài)成員初始化語(yǔ)句(包括代碼塊,按照在類(lèi)定義中的順序執(zhí)行)->子類(lèi)構(gòu)造方法()
注意哦!
如果這個(gè)類(lèi)有父類(lèi)不光是先實(shí)例化父類(lèi)。整體流程如下:
1. 加載父類(lèi)
1.1 為靜態(tài)屬性分配存儲(chǔ)空間并賦初始值
1.2 執(zhí)行靜態(tài)初始化塊和靜態(tài)初始化語(yǔ)句(從上至下)
2. 加載子類(lèi)
2.1 為靜態(tài)屬性分配存儲(chǔ)空間
2.2 執(zhí)行靜態(tài)初始化塊和靜態(tài)初始化語(yǔ)句(從上至下)
3. 加載父類(lèi)構(gòu)造器
3.1 為實(shí)例屬性分配存數(shù)空間并賦初始值
3.2 執(zhí)行實(shí)例初始化塊和實(shí)例初始化語(yǔ)句
3.3 執(zhí)行構(gòu)造器內(nèi)容
4. 加載子類(lèi)構(gòu)造器
4.1 為實(shí)例屬性分配存數(shù)空間并賦初始值
4.2 執(zhí)行實(shí)例初始化塊和實(shí)例初始化語(yǔ)句
4.3 執(zhí)行構(gòu)造器內(nèi)容
實(shí)例化的內(nèi)存模型
到這里,我們就非常的清楚為什么在靜態(tài)方法中不能直接調(diào)用非靜態(tài)的變量,因?yàn)榇藭r(shí)的非靜態(tài)變量并沒(méi)有被賦值。
以前我在學(xué)習(xí)的時(shí)候,new一個(gè)對(duì)象出來(lái)大家總是在說(shuō),我們初始化了這個(gè)對(duì)象,然后balabala。。。
導(dǎo)致我對(duì)于初始化和實(shí)例化里的靜態(tài)變量和非靜態(tài)變量何時(shí)被賦值一直有點(diǎn)模糊。new一個(gè)對(duì)象出來(lái)準(zhǔn)確的來(lái)說(shuō)是進(jìn)行了初始化和實(shí)例化兩個(gè)步驟,這樣應(yīng)該就會(huì)清晰了很多。
初始化完成以后,類(lèi)被存放在方法區(qū),注意哦,此時(shí)并沒(méi)有存放在堆內(nèi)存中。
只有當(dāng)對(duì)象實(shí)例化進(jìn)入堆內(nèi)存中以后才會(huì)對(duì)非靜態(tài)變量進(jìn)行初始化賦值。
總結(jié)
這下總算吧一個(gè)類(lèi)的初始化和實(shí)例化的細(xì)節(jié)搞明白了,關(guān)于文中的方法區(qū),堆內(nèi)存等內(nèi)容,下一節(jié)再具體分析。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
使用redis的increment()方法實(shí)現(xiàn)計(jì)數(shù)器功能案例
這篇文章主要介紹了使用redis的increment()方法實(shí)現(xiàn)計(jì)數(shù)器功能案例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-11-11java開(kāi)發(fā)實(shí)現(xiàn)五子棋游戲
這篇文章主要為大家詳細(xì)介紹了java開(kāi)發(fā)實(shí)現(xiàn)五子棋游戲,具有雙人對(duì)戰(zhàn)和人機(jī)對(duì)戰(zhàn)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09mybatis Reflector反射類(lèi)的具體使用
Reflector類(lèi)是MyBatis反射模塊的核心,負(fù)責(zé)處理類(lèi)的元數(shù)據(jù),以實(shí)現(xiàn)屬性與數(shù)據(jù)庫(kù)字段之間靈活映射的功能,本文主要介紹了mybatis Reflector反射類(lèi)的具體使用,感興趣的可以了解一下2024-02-02Java實(shí)現(xiàn)的文件上傳下載工具類(lèi)完整實(shí)例【上傳文件自動(dòng)命名】
這篇文章主要介紹了Java實(shí)現(xiàn)的文件上傳下載工具類(lèi),結(jié)合完整實(shí)例形式分析了java針對(duì)文件上傳下載操作的相關(guān)實(shí)現(xiàn)技巧,并且針對(duì)上傳文件提供了自動(dòng)命名功能以避免文件命名重復(fù),需要的朋友可以參考下2017-11-11Spring?Security放行的接口Knife4j靜態(tài)資源的問(wèn)題小結(jié)
這篇文章主要介紹了Spring?Security使用Knife4j靜態(tài)資源的問(wèn)題小結(jié),項(xiàng)目中使用?Spring?Security?做身份認(rèn)證和授權(quán),使用?Knife4j?做接口調(diào)試,需要?Spring?Security?放行的接口記錄在?RequestMatcherConstant?類(lèi)中,感興趣的朋友跟隨小編一起看看吧2024-02-02基于 SpringBoot 實(shí)現(xiàn) MySQL 讀寫(xiě)分離的問(wèn)題
這篇文章主要介紹了基于 SpringBoot 實(shí)現(xiàn) MySQL 讀寫(xiě)分離的問(wèn)題,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02