Java十分鐘精通反射機制原理
什么是反射?
反射機制是在運行狀態中,它為Java提供一種“操作對象”的能力,在運行狀態下,通過Class文件對象,可以調用到任何類里面的屬性、方法、以及構造方法,包括私有的,所有的類在反射機制面前都是透明的
自己的概括:通過Class文件對象可以看到這個類里面的所有東西,并且可以使用和修改
反射的前提是獲取Class文件對象((字節碼對象),那么一共有三種方式獲?。?/p>
- Class.forName(“全類名”) ----通過Class類的靜態方法(最常用)
- 類名.class
- 對象.getClass()
//方式1:獲取字節碼對象,Class.forName("全類名") Class cla1 = Class.forName("Study01.Person"); //方式2: 類名.Class Class cla2 = Person.class; //方式3:對象.getClass(); Person per = new Person(); Class cla3 = per.getClass(); //這三個class對象都是由Person這個類生成的 //那么我們看一下這三個字節碼對象是不是同一個: System.out.println(cla1==cla2); System.out.println(cla2==cla3);
//輸出結果: 兩個true
結論:
- 字節碼對象在類加載的時候就產生,并且只有一個
- 無論哪種方式獲取字節碼對象都是同一個字節碼對象
通過反射來獲取類中的屬性:
獲取到Class字節碼對象后,我們就可以通過字節碼對象來獲取到我們想要獲取的類的屬性、方法、構 造方法、以及private修飾的。
部分Class方法:(全部的可以查閱官方文檔) 查閱地址:https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/lang/Class.html
Demo演示:
1、建一個Person類,里面有兩個public和兩個private的屬性(不設置構造和get/set,就是看反射能不能得到里面的值)
public class Person { private String name; //名字 private int age = 18; //年齡 public int ID = 123; //身份證 public String Sex; //性別 @Override public String toString(){ return "姓名"+name+"年齡:"+age+"ID:"+ID+"性別:"+Sex; } }
測試類:
public class Test { public static void main(String[] args) throws ClassNotFoundException { //獲取Class文件對象,用最常用的通過Class類的靜態方法 Class per = Class.forName("Test01.Person"); //這里是傳入全路徑??!從最外層的包名開始! //使用getFields()方法獲取全部被public修飾的屬性(方法上面的截圖有) //并且返回的是Field類型的數組 Field fields[] = per.getFields(); for (Field field:fields) { System.out.println(field); } } }
輸出:
我們成功的獲取到了Person類中全部public屬性
2、也可以獲取全部的屬性,包括私有的:(其他代碼就不重寫啦)
for (Field field : per.getDeclaredFields()) { System.out.println(field); }
輸出:
3、獲取公有的屬性,并且修改這個值:
Field f = per.getField("Sex"); System.out.println(f); //獲取一個對象: Object obj = per.getConstructor().newInstance(); //修改值: f.set(obj,"男"); Person p = (Person)obj; System.out.println(p.Sex);
輸出:
4、獲取私有的屬性,并且修改這個值: 這里把上面修改公有屬性的值也連起來:
Person p = (Person)obj; //獲取公有字段并調用,并修改 Field f = per.getField("Sex"); //獲取一個對象: Object obj = per.getConstructor().newInstance(); f.set(obj,"男"); //將Sex的屬性修改成了 男 //調用私有的屬性,并修改 f = per.getDeclaredField("name"); //在訪問私有的屬性的值之前,先要設置運行訪問↓ //在訪問之前忽略訪問權限的檢查,叫暴力反射 f.setAccessible(true); f.set(obj,"張三"); System.out.println("Person里面的信息是:"+p.toString()); } }
輸出:
通過反射來獲取類中的方法(公有、私有、構造):
Person類:
public class Person { private String name; //名字 private int age = 18; //年齡 public int ID = 123; //身份證 public String Sex ; //性別 //構造: public Person() {} public Person(String name, int age, int ID, String sex) { this.name = name; this.age = age; this.ID = ID; Sex = sex; } //無參公有方法: public void eat(){ System.out.println("我會吃飯"); } //有參公有方法: public void eat(String food){ System.out.println("我在吃:"+food); } //有參私有方法 private void play(String name){ System.out.println(name+"在玩"); } }
測試類:
public class Test { public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException { //獲取到Person以及父類Object里面的public方法: System.out.println("-----獲取到Person以及父類Object里面的public方法↓-----"); for (Method method : Person.class.getMethods()) { System.out.println(method); System.out.println("方法名:"+ method.getName()); } //獲取到Person里面的方法,包括私有 System.out.println("-----獲取到Person里面的方法,包括私有↓-----"); for (Method method:Person.class.getDeclaredMethods()) { System.out.println(method.getName()+" "); } //按照方法名獲取到Person中的eat方法: System.out.println("-----根據方法名獲取到Person類中的eat方法↓-----"); Method earMethod1 = Person.class.getMethod("eat"); Person per = new Person(); //通過invoke(Object,param...)來調用指定的方法 earMethod1.invoke(per); //使用反射調用有參方法; System.out.println("-----使用反射調用有參方法(傳入參數)↓-----"); Method earMethod2 = Person.class.getMethod("eat",String.class); earMethod2.invoke(per,"牛肉"); //通過暴力反射獲取到私有的play方法: System.out.println("-----通過暴力反射獲取到私有的play方法傳入參數)↓-----"); Method earMethod3 = Person.class.getDeclaredMethod("play", String.class); //在訪問私有的屬性的方法之前,先要設置運行訪問 earMethod3.setAccessible(true); earMethod3.invoke(per,"小王"); }
輸出:
-----獲取到Person以及父類Object里面的public方法↓-----
public void Test02.Person.eat(java.lang.String)
方法名:eat
public void Test02.Person.eat()
方法名:eat
public final void java.lang.Object.wait() throws java.lang.InterruptedException
方法名:wait
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
方法名:wait
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
方法名:wait
public boolean java.lang.Object.equals(java.lang.Object)
方法名:equals
public java.lang.String java.lang.Object.toString()
方法名:toString
public native int java.lang.Object.hashCode()
方法名:hashCode
public final native java.lang.Class java.lang.Object.getClass()
方法名:getClass
public final native void java.lang.Object.notify()
方法名:notify
public final native void java.lang.Object.notifyAll()
方法名:notifyAll
小結:
以上就是小應學長對反射的理解和方法的應用(當然還有很多方法,這里就不一一舉例,大家可以查看官網文檔和其他技術博客開學習),其實我剛開始接觸反射的時候也很難理解反射的概念,也是通過大量的視頻和查看其他的博客來結合每個人的見解,這篇文章也有很多不足之處,歡迎大家批評指正,一起共同進步。
當然反射也有缺點(查閱其他博客的知識):
- 性能問題: 使用反射基本上是一種解釋操作,用于字段和方法接入時要遠慢于直接代碼。因此Java反射機制主要應用在對靈活性和擴展性要求很高的系統框架上,普通程序不建議使用。
- 反射會模糊程序內部邏輯:一般開發人員希望在源代碼中看到程序內部的邏輯,反射等繞過了源代碼的技術,因而會帶來維護問題。其實反射代碼比直接的代碼更復雜。
到此這篇關于Java十分鐘精通反射機制原理的文章就介紹到這了,更多相關Java 反射機制內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Spark學習筆記 (二)Spark2.3 HA集群的分布式安裝圖文詳解
這篇文章主要介紹了Spark2.3 HA集群的分布式安裝,結合圖文與實例形式詳細分析了Spark2.3 HA集群分布式安裝具體下載、安裝、配置、啟動及執行spark程序等相關操作技巧,需要的朋友可以參考下2020-02-02mybatis調用mysql存儲過程(返回參數,單結果集,多結果集)
本文主要介紹了mybatis調用mysql存儲過程(返回參數,單結果集,多結果集),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-01-01使用springboot的jar包能夠以service方式啟動
這篇文章主要介紹了使用springboot的jar包能夠以service方式啟動,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10springboot+rabbitmq實現指定消費者才能消費的方法
當項目部署到測試環境后,QA測試過程中,總是“莫名其妙”的發現所保存的用戶付款單數據有問題。這篇文章主要介紹了springboot+rabbitmq實現指定消費者才能消費,需要的朋友可以參考下2021-11-11
最新評論