【Java】反射 & 反射效能 & 反射操作泛型 & 反射操作註解
阿新 • • 發佈:2018-12-12
反射機制
- 執行時載入,探知,使用編譯期間完全未知的類。
- 程式在執行狀態中,可以動態載入一個只有名稱的類,對於任意一個已載入的類,都能夠知道這個類的所有屬性和方法,對於任意一個物件,都能夠呼叫他的任意一個方法和屬性。
- jvm載入完類之後,在堆記憶體中,就產生了一個對應的Class型別的物件,這個物件就包含了完整的類的結構資訊。Class(大寫c)是一個類。
- 一個類只有一個Class反射物件。
反射的使用
首先定義一個類User作為例子
package Reflection; public class User { public int id; private int age; String name; public User(){ } public User(int id, int age, String name) { this.id = id; this.age = age; this.name = name; } public int getId() { return id; } public void setId(int id) { this.id = id; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
有三種方式來獲得某一個類的Class物件
/方式1
Class<?> demo1 = Class.forName(path);
//方式2
Class demo2 = Reflection.User.class;
//方式3
Class demo3 = path.getClass();
獲取類的名字
demo1.getName();//獲得類名+包名
demo1.getSimpleName();//獲得類名
獲得屬性資訊
Field[] fields1 = demo1.getFields();//只能獲得public的屬性 Field[] fields2 = demo1.getDeclaredFields();//獲得所有屬性 Field field3 = demo1.getDeclaredField("name");//獲取指定屬性
獲取方法資訊同屬性,把Field換為Method
如果方法有引數,必須傳入引數型別對應的Class物件
Method method = demo1.getDeclaredMethod("setAge", int.class);
通過反射API呼叫構造方法,構造物件
User u1 = (User)demo1.newInstance();//其實是呼叫了User的無參構造 Constructor constructor = demo1.getDeclaredConstructor(int.class,int.class,String.class); User u2 = (User) constructor.newInstance(001,18,"yst");//利用有參構造,利用newInstance傳參
通過反射API呼叫普通方法,好處是可以動態的呼叫方法,例如從其他地方傳過來再放到引數中
User u3 = (User)demo1.newInstance();
Method method2 = demo1.getDeclaredMethod("setName", String.class);
method2.invoke(u3,"yst222");
通過反射API操作屬性
因為定義age屬性為private,所以set不能訪問,要用setAccessible取消安全檢查
User u4 = (User)demo1.newInstance();
Field f = demo1.getDeclaredField("age");
f.setAccessible(true);
f.set(u4,22);
反射效能
經過測試,使用反射呼叫方法所用時間遠大於直接呼叫方法,所以當需要頻繁呼叫反射的時候可以取消安全檢查,這樣使效率提高4倍。
Class.setAccessible(true); 這樣就可以取消安全檢查。
反射操作泛型
package Reflection;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
public class ReflectionGenerics {
public void test1(Map<String,Reflection.User> map, List<Reflection.User> list){
System.out.println("test1");
}
public Map<Integer,Reflection.User>test2(){
System.out.println("test2");
return null;
}
public static void main(String[] args) {
try {
//獲得指定方法引數泛型資訊
Method m = ReflectionGenerics.class.getMethod("test1",Map.class,List.class);
//獲得泛型引數型別
Type[] t = m.getGenericParameterTypes();
for (Type x: t) {
System.out.println("#"+x);
//如果是一個引數型別
if(x instanceof ParameterizedType){
//強制型別轉換
Type[] genericTypes = ((ParameterizedType)x).getActualTypeArguments();
for(Type y : genericTypes){
System.out.println("泛型型別:"+y);
}
}
}
//獲得指定方法返回值泛型資訊
Method m2 = ReflectionGenerics.class.getMethod("test02", null);
Type returnType = m2.getGenericReturnType();
if(returnType instanceof ParameterizedType){
Type[] genericTypes = ((ParameterizedType) returnType).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("返回值,泛型型別:"+genericType);
}
}
}catch (Exception e){
e.printStackTrace();
}
}
}