Java反射機(jī)制
在運(yùn)行狀態(tài)中脓钾,對(duì)于任意一個(gè)類(lèi)售睹,都能夠知道這個(gè)類(lèi)的所有屬性和方法;對(duì)于任意一個(gè)對(duì)象可训,都能夠調(diào)用它的任意方法和屬性昌妹;這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱(chēng)為Java語(yǔ)言的反射機(jī)制捶枢。
簡(jiǎn)而言之:就是把類(lèi)里面的方法變量轉(zhuǎn)化成
public void sayHi(String helloSententce) {
System.out.println(helloSententce + " " + name);
}
...
private String throwHello(String tag) {
return "hello " + tag;
}
//調(diào)用實(shí)現(xiàn)以上方法
Class<?> rc = Class.forName("com.czb.Robot");
System.out.println(rc.getName());
Robot r = (Robot) rc.getDeclaredConstructor().newInstance();
Method getHello =rc.getDeclaredMethod("throwHello", String.class);
getHello.setAccessible(true);
//invoke默認(rèn)返回Object
Object str = getHello.invoke(r,"Bob");
System.out.println("getHelloresult is "+str);
Method sayHi = rc.getMethod("sayHi", String.class);
Field name = rc.getDeclaredField("name");
name.setAccessible(true);
name.set(r,"ALice");
sayHi.invoke(r,"Welcome");
getDeclaredMethod
來(lái)獲取除了繼承或?qū)崿F(xiàn)的的所有方法
getMethod
只能獲取public方法,包括繼承或者實(shí)現(xiàn)的方法
ClassLoader的作用
通過(guò)將.class
文件的二進(jìn)制數(shù)據(jù)流裝載進(jìn)系統(tǒng)飞崖,然后交給Java虛擬機(jī)進(jìn)行連接烂叔、初始化等操作。
1.BootstrapClassloader
:C++編寫(xiě)固歪,加載核心庫(kù)java.*
2.ExtClassLoader
:Java編寫(xiě)长已,加載擴(kuò)展庫(kù)javax.*
3.AppClassLoader
:Java編寫(xiě),加載程序所在目錄昼牛,加載路徑(classpath)
4.自定義ClassLoader
:Java編寫(xiě)
為什么要使用雙親委派機(jī)制去加載類(lèi)
避免多分同樣的字節(jié)碼的加載
例如:System靜態(tài)Class字節(jié)碼术瓮,只需要一份就可以了,第一次加載是在BootstrapClassLoader
隱式加載:new
顯示加載:loadClass贰健,forName
Java9之前newInstentce生成實(shí)例
Java9之后getDeclaredConstructor().newInstance()
▲類(lèi)裝載過(guò)程(比較loadClass和forName)
1.ClassLoader加載.class胞四,生成Class對(duì)象,
加載到內(nèi)存中伶椿,并將這些靜態(tài)數(shù)據(jù)轉(zhuǎn)化成運(yùn)行時(shí)數(shù)據(jù)區(qū)中方法區(qū)的類(lèi)型數(shù)據(jù)辜伟,在運(yùn)行時(shí),數(shù)據(jù)區(qū)堆中生成一個(gè)代表這個(gè)類(lèi)的Java.lang.class對(duì)象作為方法區(qū)類(lèi)數(shù)據(jù)的訪問(wèn)入口
2.鏈接:
校驗(yàn):檢查加載的class的正確性和安全性脊另;
準(zhǔn)備:為類(lèi)變量分配存儲(chǔ)空間并設(shè)置類(lèi)變量初始值导狡,類(lèi)變量(static)隨類(lèi)型信息存放在方法區(qū)中,生命周期很長(zhǎng)偎痛,使用不當(dāng)容易造成內(nèi)存泄漏
解析:JVM將常量池內(nèi)的符號(hào)引用轉(zhuǎn)換為直接引用(不一定非要解析)
3.初始化:執(zhí)行類(lèi)變量賦值和靜態(tài)代碼塊
▲forName初始化完畢旱捧,loadClass只完成加載,還沒(méi)有鏈接
loadClass可以快速加載配置文件踩麦;
如果你要連接Mysql枚赡,driver有一段static代碼段,所以要用forName進(jìn)行加載(因?yàn)殪o態(tài)代碼段是第三步初始化里面完成的)
▲Java內(nèi)存模型(JDK8)
私有內(nèi)存區(qū)域
1.程序計(jì)數(shù)器(線(xiàn)程私有谓谦,不會(huì)內(nèi)存溢出)
當(dāng)前線(xiàn)程所執(zhí)行的字節(jié)碼行號(hào)指示器(邏輯)
通過(guò)改變計(jì)數(shù)器的值來(lái)選取下一條需要執(zhí)行的字節(jié)碼指令(分支贫橙、循環(huán)、跳轉(zhuǎn)反粥、異常處理卢肃、線(xiàn)程恢復(fù))
對(duì)Java方法計(jì)數(shù),如果是Native方法才顿,計(jì)數(shù)器的值為Undefined
2.Java虛擬機(jī)棧(線(xiàn)程私有)
Java方法執(zhí)行的內(nèi)存模型
每個(gè)方法(字節(jié)碼指令)執(zhí)行時(shí)莫湘,都會(huì)創(chuàng)建一個(gè)棧幀(存儲(chǔ):局部變量表、操作數(shù)棧娜膘、動(dòng)態(tài)連接逊脯、返回地址),棧幀持有局部變量和部分結(jié)果以及參與結(jié)果的調(diào)用和返回竣贪,方法調(diào)用結(jié)束時(shí)军洼,棧幀就會(huì)被銷(xiāo)毀
局部變量表:包含了方法執(zhí)行過(guò)程中的所有變量
操作數(shù)棧:在執(zhí)行字節(jié)碼指令過(guò)程中巩螃,類(lèi)似原生CPU寄存器,JVM字節(jié)碼大部分時(shí)間都在操作數(shù)棧的操作上(入棧匕争、出棧避乏、復(fù)制、交換甘桑、產(chǎn)生消費(fèi)變量)拍皮,
3.本地方法棧
native方法
共享內(nèi)存區(qū)域
1.元空間(MetaSpace)和永久代(PermGen)
兩者都是來(lái)存儲(chǔ)class的相關(guān)信息(Methon和Field),
▲‘兩者均是方法區(qū)的實(shí)現(xiàn)跑杭,Java 8
之后元空間
替代了永久帶
元空間用的是本地內(nèi)存铆帽,永久帶用的是JVM內(nèi)存,也就是說(shuō)本地內(nèi)存多大德谅,理論上元空間就可以有多大爹橱,這樣就直接解決了空間不足的問(wèn)題
●字符串常量池存在永久帶
中,容易出現(xiàn)性能問(wèn)題和內(nèi)存溢出
●類(lèi)和方法的信息大小難以確定窄做,給永久帶的大小指定帶來(lái)困難
●永久帶
會(huì)為GC帶來(lái)不必要的復(fù)雜性愧驱,回收效率偏低
●方便HotSpot
與其他JVM
如Jrockit
的繼承
Java堆(Heap)
存放對(duì)象實(shí)例
物理內(nèi)存可以不連續(xù)
是GC管理的主要區(qū)域(GC堆,垃圾堆)
●方法區(qū)(No-Heap)存在堆里
JVM 三大性能調(diào)優(yōu)參數(shù)-Xms椭盏, -Xmx组砚, -Xss
-Xms:堆的初始值(不夠會(huì)擴(kuò)容,擴(kuò)容時(shí)會(huì)內(nèi)存抖動(dòng))
-Xmx:堆能到達(dá)的最大值
-Xss:規(guī)定每個(gè)線(xiàn)程虛擬機(jī)棧(及堆棧)的大刑图铡(一般情況256k就可以了糟红,會(huì)影響并發(fā)線(xiàn)程數(shù)的大小)
Java內(nèi)存中堆和棧的區(qū)別
靜態(tài)存儲(chǔ):編譯時(shí)確定每個(gè)數(shù)據(jù)目標(biāo)在運(yùn)行時(shí)的存儲(chǔ)空間需求
棧式存儲(chǔ):數(shù)據(jù)區(qū)需求在編譯的時(shí)候未知蚯舱,運(yùn)行時(shí)進(jìn)入一個(gè)程序模塊前必須知道其大小
堆式存儲(chǔ):編譯時(shí)改化、運(yùn)行時(shí)都不知道所需內(nèi)存大小掩蛤,動(dòng)態(tài)分配
●存儲(chǔ)
堆:創(chuàng)建好的對(duì)象和數(shù)組都會(huì)存到堆里面
棧:基本數(shù)據(jù)類(lèi)型枉昏,引用對(duì)象、數(shù)組時(shí)揍鸟,棧定義變量保存在堆中目標(biāo)的首地址兄裂,局部變量,參數(shù)放在堆棧里面阳藻。
●管理方式
棧自動(dòng)釋放晰奖,堆需要GC
●空間
棧比堆小
●碎片相關(guān)
棧產(chǎn)生的碎片遠(yuǎn)小于小于堆(GC垃圾回收器不是實(shí)時(shí)的)
●分配方式
棧支持靜態(tài)分配和動(dòng)態(tài)分配,而堆只支持動(dòng)態(tài)分配
●效率
棧比堆效率高腥泥,棧不夠靈活
intern函數(shù)到j(luò)dk6+后的改變
如果先前在常量池已經(jīng)創(chuàng)建了匾南,則返回池中該字符串的引用。
(Java 7之后常量池從方法區(qū)(之前還是永久帶
)移到了堆里面)
String s1 = new ("asasas")//
s1.intern();
String s2 = "asasas";
"asasas"
否則就看他在不在Java堆里面蛔外,如果有就添加到常量池并返回該引用蛆楞,如果堆里面沒(méi)有溯乒,就在池里創(chuàng)建并返回引用(多了一個(gè)創(chuàng)建)