java反射深入剖析(推薦)
本篇文章依舊采用小例子來說明,因?yàn)槲沂冀K覺的,案例驅(qū)動(dòng)是最好的,要不然只看理論的話,看了也不懂,不過建議大家在看完文章之后,在回過頭去看看理論,會(huì)有更好的理解。
下面開始正文。
【案例1】通過一個(gè)對(duì)象獲得完整的包名和類名
package Reflect; /** * 通過一個(gè)對(duì)象獲得完整的包名和類名 * */ class Demo{ //other codes... } class hello{ public static void main(String[] args) { Demo demo=new Demo(); System.out.println(demo.getClass().getName()); } }
【運(yùn)行結(jié)果】:Reflect.Demo
添加一句:所有類的對(duì)象其實(shí)都是Class的實(shí)例。
【案例2】實(shí)例化Class類對(duì)象
package Reflect; class Demo{ //other codes... } class hello{ public static void main(String[] args) { Class<?> demo1=null; Class<?> demo2=null; Class<?> demo3=null; try{ //一般盡量采用這種形式 demo1=Class.forName("Reflect.Demo"); }catch(Exception e){ e.printStackTrace(); } demo2=new Demo().getClass(); demo3=Demo.class; System.out.println("類名稱 "+demo1.getName()); System.out.println("類名稱 "+demo2.getName()); System.out.println("類名稱 "+demo3.getName()); } }
【運(yùn)行結(jié)果】:
類名稱 Reflect.Demo
類名稱 Reflect.Demo
類名稱 Reflect.Demo
【案例3】通過Class實(shí)例化其他類的對(duì)象
通過無參構(gòu)造實(shí)例化對(duì)象
public Person(String name, int age) { this.age=age; this.name=name; }
然后繼續(xù)運(yùn)行上面的程序,會(huì)出現(xiàn):
所以大家以后再編寫使用Class實(shí)例化其他類的對(duì)象的時(shí)候,一定要自己定義無參的構(gòu)造函數(shù)
【案例】通過Class調(diào)用其他類中的構(gòu)造函數(shù) (也可以通過這種方式通過Class創(chuàng)建其他類的對(duì)象)
package Reflect; import java.lang.reflect.Constructor; class Person{ public Person() { } public Person(String name){ this.name=name; } public Person(int age){ this.age=age; } public Person(String name, int age) { this.age=age; this.name=name; } public String getName() { return name; } public int getAge() { return age; } @Override public String toString(){ return "["+this.name+" "+this.age+"]"; } private String name; private int age; } class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); }catch (Exception e) { e.printStackTrace(); } Person per1=null; Person per2=null; Person per3=null; Person per4=null; //取得全部的構(gòu)造函數(shù) Constructor<?> cons[]=demo.getConstructors(); try{ per1=(Person)cons[0].newInstance(); per2=(Person)cons[1].newInstance("Rollen"); per3=(Person)cons[2].newInstance(20); per4=(Person)cons[3].newInstance("Rollen",20); }catch(Exception e){ e.printStackTrace(); } System.out.println(per1); System.out.println(per2); System.out.println(per3); System.out.println(per4); } }
【運(yùn)行結(jié)果】:
[null 0]
[Rollen 0]
[null 20]
[Rollen 20]
【案例】
返回一個(gè)類實(shí)現(xiàn)的接口:
package Reflect; interface China{ public static final String name="Rollen"; public static int age=20; public void sayChina(); public void sayHello(String name, int age); } class Person implements China{ public Person() { } public Person(String sex){ this.sex=sex; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public void sayChina(){ System.out.println("hello ,china"); } @Override public void sayHello(String name, int age){ System.out.println(name+" "+age); } private String sex; } class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); }catch (Exception e) { e.printStackTrace(); } //保存所有的接口 Class<?> intes[]=demo.getInterfaces(); for (int i = 0; i < intes.length; i++) { System.out.println("實(shí)現(xiàn)的接口 "+intes[i].getName()); } } }
【運(yùn)行結(jié)果】:
實(shí)現(xiàn)的接口 Reflect.China
(注意,以下幾個(gè)例子,都會(huì)用到這個(gè)例子的Person類,所以為節(jié)省篇幅,此處不再粘貼Person的代碼部分,只粘貼主類hello的代碼)
【案例】:取得其他類中的父類
class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); }catch (Exception e) { e.printStackTrace(); } //取得父類 Class<?> temp=demo.getSuperclass(); System.out.println("繼承的父類為: "+temp.getName()); } }
【運(yùn)行結(jié)果】
繼承的父類為: java.lang.Object
【案例】:獲得其他類中的全部構(gòu)造函數(shù)
這個(gè)例子需要在程序開頭添加import java.lang.reflect.*;
然后將主類編寫為:
class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); }catch (Exception e) { e.printStackTrace(); } Constructor<?>cons[]=demo.getConstructors(); for (int i = 0; i < cons.length; i++) { System.out.println("構(gòu)造方法: "+cons[i]); } } }
【運(yùn)行結(jié)果】:
構(gòu)造方法: public Reflect.Person()
構(gòu)造方法: public Reflect.Person(java.lang.String)
但是細(xì)心的讀者會(huì)發(fā)現(xiàn),上面的構(gòu)造函數(shù)沒有public 或者private這一類的修飾符
下面這個(gè)例子我們就來獲取修飾符
class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); }catch (Exception e) { e.printStackTrace(); } Constructor<?>cons[]=demo.getConstructors(); for (int i = 0; i < cons.length; i++) { Class<?> p[]=cons[i].getParameterTypes(); System.out.print("構(gòu)造方法: "); int mo=cons[i].getModifiers(); System.out.print(Modifier.toString(mo)+" "); System.out.print(cons[i].getName()); System.out.print("("); for(int j=0;j<p.length;++j){ System.out.print(p[j].getName()+" arg"+i); if(j<p.length-1){ System.out.print(","); } } System.out.println("){}"); } } }
【運(yùn)行結(jié)果】:
構(gòu)造方法: public Reflect.Person(){}
構(gòu)造方法: public Reflect.Person(java.lang.String arg1){}
有時(shí)候一個(gè)方法可能還有異常,呵呵。下面看看:
class hello{ public static void main(String[] args) { Class<?> demo=null; try{ demo=Class.forName("Reflect.Person"); }catch (Exception e) { e.printStackTrace(); } Method method[]=demo.getMethods(); for(int i=0;i<method.length;++i){ Class<?> returnType=method[i].getReturnType(); Class<?> para[]=method[i].getParameterTypes(); int temp=method[i].getModifiers(); System.out.print(Modifier.toString(temp)+" "); System.out.print(returnType.getName()+" "); System.out.print(method[i].getName()+" "); System.out.print("("); for(int j=0;j<para.length;++j){ System.out.print(para[j].getName()+" "+"arg"+j); if(j<para.length-1){ System.out.print(","); } } Class<?> exce[]=method[i].getExceptionTypes(); if(exce.length>0){ System.out.print(") throws "); for(int k=0;k<exce.length;++k){ System.out.print(exce[k].getName()+" "); if(k<exce.length-1){ System.out.print(","); } } }else{ System.out.print(")"); } System.out.println(); } } }
【案例】接下來讓我們?nèi)〉闷渌惖娜繉傩园桑詈笪抑v這些整理在一起,也就是通過class取得一個(gè)類的全部框架
class hello { public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } System.out.println("===============本類屬性========================"); // 取得本類的全部屬性 Field[] field = demo.getDeclaredFields(); for (int i = 0; i < field.length; i++) { // 權(quán)限修飾符 int mo = field[i].getModifiers(); String priv = Modifier.toString(mo); // 屬性類型 Class<?> type = field[i].getType(); System.out.println(priv + " " + type.getName() + " " + field[i].getName() + ";"); } System.out.println("===============實(shí)現(xiàn)的接口或者父類的屬性========================"); // 取得實(shí)現(xiàn)的接口或者父類的屬性 Field[] filed1 = demo.getFields(); for (int j = 0; j < filed1.length; j++) { // 權(quán)限修飾符 int mo = filed1[j].getModifiers(); String priv = Modifier.toString(mo); // 屬性類型 Class<?> type = filed1[j].getType(); System.out.println(priv + " " + type.getName() + " " + filed1[j].getName() + ";"); } } }
【運(yùn)行結(jié)果】:
===============本類屬性========================
private java.lang.String sex;
===============實(shí)現(xiàn)的接口或者父類的屬性========================
public static final java.lang.String name;
public static final int age;
【案例】其實(shí)還可以通過反射調(diào)用其他類中的方法:
class hello { public static void main(String[] args) { Class<?> demo = null; try { demo = Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } try{ //調(diào)用Person類中的sayChina方法 Method method=demo.getMethod("sayChina"); method.invoke(demo.newInstance()); //調(diào)用Person的sayHello方法 method=demo.getMethod("sayHello", String.class,int.class); method.invoke(demo.newInstance(),"Rollen",20); }catch (Exception e) { e.printStackTrace(); } } }
【運(yùn)行結(jié)果】:
hello ,china
Rollen 20
【案例】調(diào)用其他類的set和get方法
class hello { public static void main(String[] args) { Class<?> demo = null; Object obj=null; try { demo = Class.forName("Reflect.Person"); } catch (Exception e) { e.printStackTrace(); } try{ obj=demo.newInstance(); }catch (Exception e) { e.printStackTrace(); } setter(obj,"Sex","男",String.class); getter(obj,"Sex"); } /** * @param obj * 操作的對(duì)象 * @param att * 操作的屬性 * */ public static void getter(Object obj, String att) { try { Method method = obj.getClass().getMethod("get" + att); System.out.println(method.invoke(obj)); } catch (Exception e) { e.printStackTrace(); } } /** * @param obj * 操作的對(duì)象 * @param att * 操作的屬性 * @param value * 設(shè)置的值 * @param type * 參數(shù)的屬性 * */ public static void setter(Object obj, String att, Object value, Class<?> type) { try { Method method = obj.getClass().getMethod("set" + att, type); method.invoke(obj, value); } catch (Exception e) { e.printStackTrace(); } } }// end class
【運(yùn)行結(jié)果】:
男
【案例】通過反射操作屬性
class hello { public static void main(String[] args) throws Exception { Class<?> demo = null; Object obj = null; demo = Class.forName("Reflect.Person"); obj = demo.newInstance(); Field field = demo.getDeclaredField("sex"); field.setAccessible(true); field.set(obj, "男"); System.out.println(field.get(obj)); } }// end class
【案例】通過反射取得并修改數(shù)組的信息:
import java.lang.reflect.*; class hello{ public static void main(String[] args) { int[] temp={1,2,3,4,5}; Class<?>demo=temp.getClass().getComponentType(); System.out.println("數(shù)組類型: "+demo.getName()); System.out.println("數(shù)組長(zhǎng)度 "+Array.getLength(temp)); System.out.println("數(shù)組的第一個(gè)元素: "+Array.get(temp, 0)); Array.set(temp, 0, 100); System.out.println("修改之后數(shù)組第一個(gè)元素為: "+Array.get(temp, 0)); } }
【運(yùn)行結(jié)果】:
數(shù)組類型: int
數(shù)組長(zhǎng)度 5
數(shù)組的第一個(gè)元素: 1
修改之后數(shù)組第一個(gè)元素為: 100
【案例】通過反射修改數(shù)組大小
class hello{ public static void main(String[] args) { int[] temp={1,2,3,4,5,6,7,8,9}; int[] newTemp=(int[])arrayInc(temp,15); print(newTemp); System.out.println("====================="); String[] atr={"a","b","c"}; String[] str1=(String[])arrayInc(atr,8); print(str1); } /** * 修改數(shù)組大小 * */ public static Object arrayInc(Object obj,int len){ Class<?>arr=obj.getClass().getComponentType(); Object newArr=Array.newInstance(arr, len); int co=Array.getLength(obj); System.arraycopy(obj, 0, newArr, 0, co); return newArr; } /** * 打印 * */ public static void print(Object obj){ Class<?>c=obj.getClass(); if(!c.isArray()){ return; } System.out.println("數(shù)組長(zhǎng)度為: "+Array.getLength(obj)); for (int i = 0; i < Array.getLength(obj); i++) { System.out.print(Array.get(obj, i)+" "); } } }
【運(yùn)行結(jié)果】:
數(shù)組長(zhǎng)度為: 15
1 2 3 4 5 6 7 8 9 0 0 0 0 0 0 =====================
數(shù)組長(zhǎng)度為: 8
a b c null null null null null
動(dòng)態(tài)代理
【案例】首先來看看如何獲得類加載器:
class test{ } class hello{ public static void main(String[] args) { test t=new test(); System.out.println("類加載器 "+t.getClass().getClassLoader().getClass().getName()); } }
【程序輸出】:
類加載器 sun.misc.Launcher$AppClassLoader
其實(shí)在java中有三種類類加載器。
1)Bootstrap ClassLoader 此加載器采用c++編寫,一般開發(fā)中很少見。
2)Extension ClassLoader 用來進(jìn)行擴(kuò)展類的加載,一般對(duì)應(yīng)的是jre\lib\ext目錄中的類
3)AppClassLoader 加載classpath指定的類,是最常用的加載器。同時(shí)也是java中默認(rèn)的加載器。
如果想要完成動(dòng)態(tài)代理,首先需要定義一個(gè)InvocationHandler接口的子類,已完成代理的具體操作。
package Reflect; import java.lang.reflect.*; //定義項(xiàng)目接口 interface Subject { public String say(String name, int age); } // 定義真實(shí)項(xiàng)目 class RealSubject implements Subject { @Override public String say(String name, int age) { return name + " " + age; } } class MyInvocationHandler implements InvocationHandler { private Object obj = null; public Object bind(Object obj) { this.obj = obj; return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj .getClass().getInterfaces(), this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object temp = method.invoke(this.obj, args); return temp; } } class hello { public static void main(String[] args) { MyInvocationHandler demo = new MyInvocationHandler(); Subject sub = (Subject) demo.bind(new RealSubject()); String info = sub.say("Rollen", 20); System.out.println(info); } }
【運(yùn)行結(jié)果】:
Rollen 20
類的生命周期
在一個(gè)類編譯完成之后,下一步就需要開始使用類,如果要使用一個(gè)類,肯定離不開JVM。在程序執(zhí)行中JVM通過裝載,鏈接,初始化這3個(gè)步驟完成。
類的裝載是通過類加載器完成的,加載器將.class文件的二進(jìn)制文件裝入JVM的方法區(qū),并且在堆區(qū)創(chuàng)建描述這個(gè)類的java.lang.Class對(duì)象。用來封裝數(shù)據(jù)。 但是同一個(gè)類只會(huì)被類裝載器裝載以前
鏈接就是把二進(jìn)制數(shù)據(jù)組裝為可以運(yùn)行的狀態(tài)。
鏈接分為校驗(yàn),準(zhǔn)備,解析這3個(gè)階段
校驗(yàn)一般用來確認(rèn)此二進(jìn)制文件是否適合當(dāng)前的JVM(版本),
準(zhǔn)備就是為靜態(tài)成員分配內(nèi)存空間,。并設(shè)置默認(rèn)值
解析指的是轉(zhuǎn)換常量池中的代碼作為直接引用的過程,直到所有的符號(hào)引用都可以被運(yùn)行程序使用(建立完整的對(duì)應(yīng)關(guān)系)
完成之后,類型也就完成了初始化,初始化之后類的對(duì)象就可以正常使用了,直到一個(gè)對(duì)象不再使用之后,將被垃圾回收。釋放空間。
當(dāng)沒有任何引用指向Class對(duì)象時(shí)就會(huì)被卸載,結(jié)束類的生命周期
將反射用于工廠模式
先來看看,如果不用反射的時(shí)候,的工廠模式吧:
/** * @author Rollen-Holt 設(shè)計(jì)模式之 工廠模式 */ interface fruit{ public abstract void eat(); } class Apple implements fruit{ public void eat(){ System.out.println("Apple"); } } class Orange implements fruit{ public void eat(){ System.out.println("Orange"); } } // 構(gòu)造工廠類 // 也就是說以后如果我們?cè)谔砑悠渌膶?shí)例的時(shí)候只需要修改工廠類就行了 class Factory{ public static fruit getInstance(String fruitName){ fruit f=null; if("Apple".equals(fruitName)){ f=new Apple(); } if("Orange".equals(fruitName)){ f=new Orange(); } return f; } } class hello{ public static void main(String[] a){ fruit f=Factory.getInstance("Orange"); f.eat(); } }
這樣,當(dāng)我們?cè)谔砑右粋€(gè)子類的時(shí)候,就需要修改工廠類了。如果我們添加太多的子類的時(shí)候,改的就會(huì)很多。
現(xiàn)在我們看看利用反射機(jī)制:
package Reflect; interface fruit{ public abstract void eat(); } class Apple implements fruit{ public void eat(){ System.out.println("Apple"); } } class Orange implements fruit{ public void eat(){ System.out.println("Orange"); } } class Factory{ public static fruit getInstance(String ClassName){ fruit f=null; try{ f=(fruit)Class.forName(ClassName).newInstance(); }catch (Exception e) { e.printStackTrace(); } return f; } } class hello{ public static void main(String[] a){ fruit f=Factory.getInstance("Reflect.Apple"); if(f!=null){ f.eat(); } } }
現(xiàn)在就算我們添加任意多個(gè)子類的時(shí)候,工廠類就不需要修改。
上面的愛嗎雖然可以通過反射取得接口的實(shí)例,但是需要傳入完整的包和類名。而且用戶也無法知道一個(gè)接口有多少個(gè)可以使用的子類,所以我們通過屬性文件的形式配置所需要的子類。
下面我們來看看: 結(jié)合屬性文件的工廠模式
首先創(chuàng)建一個(gè)fruit.properties的資源文件,
內(nèi)容為:
apple=Reflect.Apple orange=Reflect.Orange
然后編寫主類代碼:
package Reflect; import java.io.*; import java.util.*; interface fruit{ public abstract void eat(); } class Apple implements fruit{ public void eat(){ System.out.println("Apple"); } } class Orange implements fruit{ public void eat(){ System.out.println("Orange"); } } //操作屬性文件類 class init{ public static Properties getPro() throws FileNotFoundException, IOException{ Properties pro=new Properties(); File f=new File("fruit.properties"); if(f.exists()){ pro.load(new FileInputStream(f)); }else{ pro.setProperty("apple", "Reflect.Apple"); pro.setProperty("orange", "Reflect.Orange"); pro.store(new FileOutputStream(f), "FRUIT CLASS"); } return pro; } } class Factory{ public static fruit getInstance(String ClassName){ fruit f=null; try{ f=(fruit)Class.forName(ClassName).newInstance(); }catch (Exception e) { e.printStackTrace(); } return f; } } class hello{ public static void main(String[] a) throws FileNotFoundException, IOException{ Properties pro=init.getPro(); fruit f=Factory.getInstance(pro.getProperty("apple")); if(f!=null){ f.eat(); } } }
以上這篇java反射深入剖析(推薦)就是小編分享給大家的全部?jī)?nèi)容了,希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot如何根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間
這篇文章主要介紹了SpringBoot如何根據(jù)用戶系統(tǒng)時(shí)區(qū)動(dòng)態(tài)展示時(shí)間,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-01-01springcloud中Ribbon和RestTemplate實(shí)現(xiàn)服務(wù)調(diào)用與負(fù)載均衡
這篇文章主要介紹了Ribbon和RestTemplate實(shí)現(xiàn)服務(wù)調(diào)用與負(fù)載均衡,想了解負(fù)載均衡的同學(xué)可以參考下2021-04-04Spring學(xué)習(xí)筆記1之IOC詳解盡量使用注解以及java代碼
這篇文章主要介紹了Spring學(xué)習(xí)筆記1之IOC詳解盡量使用注解以及java代碼 的相關(guān)資料,需要的朋友可以參考下2016-07-07基于Java方式實(shí)現(xiàn)數(shù)據(jù)同步
這篇文章主要為大家詳細(xì)介紹了基于Java方式實(shí)現(xiàn)數(shù)據(jù)同步,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-08-08Spring事件發(fā)布監(jiān)聽,順序監(jiān)聽,異步監(jiān)聽方式
這篇文章主要介紹了Spring事件發(fā)布監(jiān)聽,順序監(jiān)聽,異步監(jiān)聽方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12Java 仿天貓服裝商城系統(tǒng)的實(shí)現(xiàn)流程
讀萬卷書不如行萬里路,只學(xué)書上的理論是遠(yuǎn)遠(yuǎn)不夠的,只有在實(shí)戰(zhàn)中才能獲得能力的提升,本篇文章手把手帶你用java+SSM+jsp+mysql+maven實(shí)現(xiàn)一個(gè)仿天貓服裝商城系統(tǒng),大家可以在過程中查缺補(bǔ)漏,提升水平2021-11-11java基于jcifs.smb實(shí)現(xiàn)遠(yuǎn)程發(fā)送文件到服務(wù)器
這篇文章主要介紹了java基于jcifs.smb實(shí)現(xiàn)遠(yuǎn)程發(fā)送文件到服務(wù)器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-01-01