本文是 Java 基礎系列的第一篇,關於 Java 反射的學習。在我們所熟知的各種框架中,都必須基於這門技術。而且在工作中,我們也會手動去封裝一些功能或者改寫一些第三方的功能,這時候熟悉掌握反射是必須的過程。希望這篇文章能幫到各位小夥伴,如有錯誤,還望指正。
反射的定義
- 反射是對類本身進一步抽象而來的。抽象是面向對象的一大特性,我們在開發中,會對某些業務屬性進行抽象,但是我們有沒有想過,類本身也是可以繼續抽象的,類們都有包名、屬性、構造器和方法等等一些共有的東西,那麼可以把他們再進一步的抽象出來。再進一步而言,Class 類是對 .class 文件字節碼的抽象,而類中的方法、屬性是單獨各自成爲一個類的。字節碼文件對應着 java 原文件,改變字節碼就意味着從根本上改變了對應的類。
- 先有Class,纔能有類中的方法、屬性等等。Class 描述類本身,Feild 類中屬性,Method 類中方法,Constructor類中構造器,Annotation類中註解,Package 類所屬的包。
反射的具體使用
1. 三種方式獲取 Class
- 通過全類名:
// 注意 class 是關鍵字
Class clazz = Class.forName("包名.類名");
- 如果不知道全類名,可以類名.class獲取:
Class clazz = 類名.class;
- 在 java 中我們通常能看到某些對象的創建是通過工廠模式或者其他的不是直接 new 對象來創建的出來的,在接收該對象的時候,可能使用的父類接收,所以我們沒辦法直接通過上述兩種方式獲取到Class。那我們可以用以下這種方式獲取:
Class clazz = 對象.getClass();
2. 用Class對象獲取類信息
如類:
package cn.joncy.reflect;
public class Hero extends Person implements A{
private String name;
public int age;
public String toString(){
return name+","+age;
}
}
- 獲取該類的修飾符
int modifiers = clazz.getModifiers(); // modifiers = 1
- 獲取類名
String name = clazz.getName(); // cn.joncy.reflect.Hero
String simpleName = clazz.getSimpleName(); // Hero
- 獲取包名
Package p = clazz.getPackage(); // cn.joncy.reflect
- 獲取父類
Class sclass = clazz.getSuperclass(); // cn.joncy.reflect.Person
- 獲取所有的父接口
Class[] classes = clazz.getInterfaces();
for(Class c:classes){
System.out.println(c.getName()); // cn.joncy.reflect.A
}
- 獲取默認無參構造方法創建對象
Class clazz = Class.forName("cn.joncy.reflect.Hero");
Hero hero = (Hero) clazz.newInstance(); //默認調用無參數構造方法創建對象
- 獲取類中屬性
// 只能獲取公有的屬性,但是包含繼承過來的父類屬性
Field nameField = clazz.getField("name");
int modifiers = nameField.getModifiers();//屬性的修飾符 1
Class fclass = nameField.getType();//獲取屬性的類型 int
String fname = nameField.getName();//獲取屬性名字 age
// 只能獲取公有的和私有的屬性,但是隻能獲取本類中的屬性
Field f = clazz.getDeclaredField("name");// name
3. 操作類屬性
Hero hero = (Hero)clazz.newInstance();
Field f = clazz.getDeclaredField("name");//name名字
// 設置
f.setAccessible(true);
f.set(hero, "jc");
// 獲取
String name = (String) f.get(hero);
4. 操作類方法
- 獲取方法中的描述
int mm = m.getModifiers(); // 修飾符
Class mrt = m.getReturnType(); // 返回值類型
String mn = m.getName(); // 方法名字
Class[] mpts = m.getParameterTypes(); // 參數列表
Class[] mets = m.getExceptionTypes(); // 異常類型
- 反射執行某個方法
Class clazz = Hero.class;
Hero h = (Hero)clazz.newInstance();
Method m = clazz.getMethod("test2",String.class);
String result = (String)m.invoke(h,"參數1");
Method m = clazz.getDeclaredMethod("test1"); //獲取本類中的私有或公有方法
System.out.println(m.getName()); // 獲取方法名字
m.setAccessible(true); // 設置使用權
m.invoke(p);
- 獲取所有公有的方法,包括父類
Method[] ms = clazz.getMethods();
5. 操作構造方法
- 獲取構造器的描述
Constructor con = clazz.getConstructor();
Constructor[] cons = clazz.getConstructors();
clazz.getDeclaredConstructor();
clazz.getDeclaredConstructors();
con.getModifiers(); // 修飾符
con.getName(); // 名字
con.getParameterTypes(); // 參數類型
con.getExceptionTypes(); // 異常類型
- 反射創建對象
Constructor con = clazz.getConstructor(String.class);
con.setAccessible(true);
Hero h = (Hero)con.newInstance("name");