這篇“Java反射機制實例分析”文章的知識點大部分人都不太理解,所以小編給大家總結(jié)了以下內(nèi)容,內(nèi)容詳細(xì),步驟清晰,具有一定的借鑒價值,希望大家閱讀完這篇文章能有所收獲,下面我們一起來看看這篇“Java反射機制實例分析”文章吧。
讓客戶滿意是我們工作的目標(biāo),不斷超越客戶的期望值來自于我們對這個行業(yè)的熱愛。我們立志把好的技術(shù)通過有效、簡單的方式提供給客戶,將通過不懈努力成為客戶在信息化領(lǐng)域值得信任、有價值的長期合作伙伴,公司提供的服務(wù)項目有:域名與空間、雅安服務(wù)器托管、營銷軟件、網(wǎng)站建設(shè)、吉利網(wǎng)站維護(hù)、網(wǎng)站推廣。
Java的反射(reflection)機制是指在程序的運行狀態(tài)中,可以構(gòu)造任意一個類的對象,可以了解任意一個對象所屬的類,可以了解任意一個類的成員變量和方法,可以調(diào)用任意一個對象的屬性和方法。這種動態(tài)獲取程序信息以及動態(tài)調(diào)用對象的功能稱為Java語言的反射機制。反射被視為動態(tài)語言的關(guān)鍵。
我不太擅長文字表達(dá),還是上圖操作把
不用反射機制的例子
//定義一個animals接口interface animals { public abstract void print();}//定義類來實現(xiàn)animals接口的抽象方法class Dog implements animals { public void print() { System.out.println("Dog"); }}class Cat implements animals { public void print() { System.out.println("Cat"); }}// 構(gòu)造一個zoo類// 之后如果我們在添加其他的實例的時候只需要修改zoo類class zoo { public static animals getInstance(String animalsName) { animals a = null; if ("Dog".equals(animalsName)) { a = new Dog(); } if ("Cat".equals(animalsName)) { a = new Cat(); } return a; }}public class reflection { public static void main(String[] args) { //借助zoo類尋找對應(yīng)的類來實現(xiàn)接口 animals a=zoo.getInstance("Cat"); if(a!=null) a.print(); }}
這時候添加動物,只需要
添加類
修改zoo
修改main函數(shù)的動物類
把上面修改為反射機制
//定義一個animals接口interface animals { public abstract void print();}//定義類來實現(xiàn)animals接口的抽象方法class Dog implements animals { public void print() { System.out.println("Dog"); }}class Cat implements animals { public void print() { System.out.println("Cat"); }}// 構(gòu)造一個zoo類// 之后如果我們在添加其他的實例的時候只需要修改zoo類class zoo { public static animals getInstance(String className) { animals a = null; try { //借助Class.forName尋找類名,并用newInstance實例化類似于new a = (animals) Class.forName(className).newInstance(); } catch (Exception e) { e.printStackTrace(); } return a; }}public class reflection { public static void main(String[] args) { //借助zoo類尋找對應(yīng)的類來實現(xiàn)接口(classname為當(dāng)前包名加類名) animals a = zoo.getInstance("com.cc1.Dog"); if (a != null) a.print(); }}
這時候添加動物只需要
添加類
修改main函數(shù)的動物類
省了一步,傳入類名可控,發(fā)現(xiàn)好像是存在的類都可以調(diào)
我們用的最多的可能是
forName(調(diào)用類)
getMethod(調(diào)用類下方法)
invoke(執(zhí)行)
newInstance(實例化對象)
Class.forName(className).getMethod(methodName).invoke(Class.forName(className).newInstance());
下面我們用反射機制來彈出計算機(calc)或者記事本(notepad)
由于彈出計算機有點多這次我就彈記事本把,總而言之,能彈出來就很美妙
Runtime.getRuntime().exec("notepad");
我們看下getRuntime函數(shù)
得知,該函數(shù)是Runtime類獲取對象的方式,個人感覺是每用一次就調(diào)一次比較麻煩,為了不調(diào)用一次建立一個對象所以封裝成了函數(shù)
類對象獲取方式
Class.forName(類名獲取)
zoo.class(已經(jīng)加載過的類)
obj.class(實例)
類初始化
修改zoo類,增加初始塊、靜態(tài)初始塊、和構(gòu)造函數(shù)
class zoo { //初始塊 { System.out.println("1 " + this.getClass()); } //靜態(tài)初始塊 static { System.out.println("2 " + zoo.class); } public zoo() { System.out.println("3 " + this.getClass()); } public static animals getInstance(String className) { animals a = null; try { //借助Class.forName尋找類名,并用newInstance實例化類似于new a = (animals) Class.forName(className).newInstance(); } catch (Exception e) { e.printStackTrace(); } return a; }}
類初始化執(zhí)行順序:靜態(tài)初始塊
類實例化執(zhí)行順序:靜態(tài)初始塊 - > 初始塊 - > 構(gòu)造函數(shù)
由此得知,類初始化和類實例化不一樣
接下來增加zoo1類繼承zoo類
class zoo1 extends zoo{ //初始塊 { System.out.println("11 " + this.getClass()); } //靜態(tài)初始塊 static { System.out.println("12 " + zoo.class); } public zoo1() { System.out.println("13 " + this.getClass()); }}
子類初始化順序:父類靜態(tài)初始化塊 - > 子類靜態(tài)初始化塊
子類實例化順序:父類靜態(tài)初始化塊 - > 子類靜態(tài)初始化塊 - > 父類初始化塊 - > 父類構(gòu)造函數(shù) - > 子類初始化塊 - >子類構(gòu)造函數(shù)
以上可以得知,當(dāng)使用Class.forName時,且類靜態(tài)初始化塊可控,可以執(zhí)行任意代碼
調(diào)用內(nèi)部類
Class.forName(“java.lang.Runtime”)來獲取類(java.lang.Runtime是Runtime類的完整路徑)
getMethod
getMethod 的作用是通過反射獲取類的某個特定的公有方法。
java支持類重載,但不能僅通過一個函數(shù)名確定一個函數(shù),所以在調(diào)用getMethod時,需要傳給它方法的參數(shù)類型列表
Class.forName(“java.lang.Runtime”).getMethod(“exec”, String.class)
invoke
靜態(tài)和動態(tài)方法的區(qū)別
invoke方法在getMethod類下,作用時傳遞參數(shù),執(zhí)行方法
public Object invoke(Object obj, Object… args)
第一個參數(shù)是getMethod獲取的方法的類對象(如果方法是靜態(tài)方法則傳類)
獲取exec函數(shù)的類對象
Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”))
由于getRuntime是靜態(tài)方法,所以傳類
invoke(Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”)),“calc.exe”)
最后我們合并一下
Class.forName("java.lang.Runtime"). getMethod("exec", String.class). invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")), "notepad");
String str="notepad";ProcessBuilder pb = new ProcessBuilder(str);pb.start();
getConsturctor(函數(shù)可以選定指定接口格式的構(gòu)造函數(shù)(由于構(gòu)造函數(shù)也可以根據(jù)參數(shù)來進(jìn)行重載)
選定后我們可以通過newInstance(),并傳入構(gòu)造函數(shù)的參數(shù)執(zhí)行構(gòu)造函數(shù)
ProcessBuilder類有兩個構(gòu)造函數(shù)
public ProcessBuilder(String… command)(String…變長的字符串?dāng)?shù)組String[].class)
public ProcessBuilder(List command)
分別使用構(gòu)造方法
Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[][]{
{“notepad”}})
Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))
執(zhí)行完構(gòu)造方法實例后,在進(jìn)行強制轉(zhuǎn)化使用start函數(shù)即可
( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();
實際中,肯定用不了,哪有這么好的事,還是接著反射把
Class.forName(“java.lang.ProcessBuilder”).getMethod(“start”).invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList(“notepad”)));
這里可能有人會好奇我寫的里那的另一個構(gòu)造函數(shù),String…command這個傳參為什么用new String[][]{{“notepad”}},不應(yīng)該是new String[]{“notepad”},現(xiàn)在用應(yīng)該的
((ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[]{“notepad”})).start();
在這行打斷點調(diào)試
我們傳的是一個字符串?dāng)?shù)組到了實例化的時候變成了一個字符串,再看看另一個構(gòu)造函數(shù)(List)
( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();
依舊還是這行打斷點
由此可知,List傳入時會被當(dāng)作Object的第一項,而String[]會被當(dāng)做Object,所以多加一層[]{}
通過函數(shù)getDeclaredConstructor獲取私有方法,再利用setAccessible(true)打破私有方法限制
Class cls = Class.forName("java.lang.Runtime"); Constructor m = cls.getDeclaredConstructor(); m.setAccessible(true); cls.getMethod("exec", String.class).invoke(m.newInstance(), "notepad");
以上就是關(guān)于“Java反射機制實例分析”這篇文章的內(nèi)容,相信大家都有了一定的了解,希望小編分享的內(nèi)容對大家有幫助,若想了解更多相關(guān)的知識內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。