一、反射機制
1.1概念
在運行狀態中,對於任意一個實體類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意方法和屬性;這種動態獲取信息以及動態調用對象方法的功能稱爲java語言的反射機制。
主要提供了以下功能:
- 在運行時判斷任意一個對象所屬的類。
- 在運行時構造任意一個類的對象。
- 在運行時判斷任意一個類所具有的成員變量和方法。
- 在運行時調用任意一個對象的方法
1.2應用場合
反射的重點在於運行時階段,可以動態加載和獲取。常見的應用場合:
- 訪問沒有權限的方法或屬性
- 編碼階段不能確定需要創建的類
- 處理註解
- 動態代理
1.3特點
優點:
提升程序的靈活性和擴展性
缺點:
破壞代碼的封裝性和可讀性
性能差。反射相當於一系列解釋操作,通知jvm要做的事情,性能比直接的java代碼要慢很多。
二、API
2.1常用類
java.lang.Class; //類
java.lang.reflect.Constructor;//構造方法
java.lang.reflect.Field; //類的成員變量
java.lang.reflect.Method;//類的方法
java.lang.reflect.Modifier;//訪問權限
2.2獲取Class對象
/**
* 方式一:調用某個對象的getClass()方法
*/
User p=new User();
Class clazz=user.getClass();
/**
* 方式二:調用某個類的class屬性來獲取該類對應的Class對象
*/
Class clazz=User.class;
/**
* 使用反射:使用Class類中的forName()靜態方法;
*/
Class clazz=Class.forName("com.lin.app.test.User");
2.3 Class API
//是否是基礎類型
boolean isPrimitive = class1.isPrimitive();
//是否是集合類
boolean isArray = class1.isArray();
//是否是註解類
boolean isAnnotation = class1.isAnnotation();
//是否是接口類
boolean isInterface = class1.isInterface();
//是否是枚舉類
boolean isEnum = class1.isEnum();
//是否是匿名內部類
boolean isAnonymousClass = class1.isAnonymousClass();
//是否被某個註解類修飾
boolean isAnnotationPresent = class1.isAnnotationPresent(Deprecated.class);
//獲取class名字 包含包名路徑
String className = class1.getName();
//獲取class的包信息
Package aPackage = class1.getPackage();
//獲取class類名
String simpleName = class1.getSimpleName();
//獲取class訪問權限
int modifiers = class1.getModifiers();
//內部類
Class<?>[] declaredClasses = class1.getDeclaredClasses();
//外部類
Class<?> declaringClass = class1.getDeclaringClass();
2.4創建類實例
/**
* 方式一:使用默認構造函數創建
* 調用Class.newInstance()
* 或通過Constructor.newInstance
*/
try {
Class clazz = User.class;
User user = (User) clazz.newInstance();
Constructor constructor = clazz.getConstructor();
User user1 = (User) constructor.newInstance();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
/**
* 方式二:使用帶參構造函數創建
* 調用Constructor.newInstance
*/
try {
Class clazz = User.class;
Constructor constructor = clazz.getDeclaredConstructor(String.class, String.class);
User user = (User) constructor.newInstance("", "");
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
2.5方法和字段相關API
常用Field API
/**
* Class:
* Field getField(String name) 獲得類聲明的指定公共字段(無法獲取Private字段)
* Field[] getFields() 獲得類聲明的所有公共字段(無法獲取Private字段)
* Field getDeclaredField(String name) 獲取類聲明的指定字段
* Field[] getDeclaredFields() 獲取類聲明的所有字段
*
* Field:
* getType() 返回這個變量的類型
* getGenericType() 如果當前屬性有簽名屬性類型就返回,否則就返回 Field.getType()
* isEnumConstant() 判斷這個屬性是否是枚舉類
* getModifiers() 獲取語言修飾符 public、private等
* getName() 獲取屬性的名字
* get(Object obj) 獲取該對象屬性值
* set(Object obj, Object value) 設置該對象屬性值
* setAccessible(boolean flag) 設置允許訪問private對象
*/
常用Method API
/**
* Class:
* getMethods(); 獲取類聲明的公共方法(無法獲取Private方法)
* getMethod(String name, Class<?>... parameterTypes) 獲取類聲明的指定公共方法(無法獲取Private方法)
* getDeclaredMethods(); 獲取類聲明的所有方法
* getDeclaredMethod(String name, Class<?>... parameterTypes) 獲取類聲明的指定方法
*
* Method:
* getDeclaringClass() 返回方法所在的Class
* getParameterTypes() 形參類型
* getExceptionTypes() 拋出的異常類型
* getReturnType() 返回類型
* getModifiers() 獲取語言修飾符 public、private等
* getName() 獲取方法名稱
* setAccessible(boolean flag) 設置允許訪問private對象
* isBridge() 是否是橋接方法
* isSynthetic() 是否是複合方法
* isVarArgs() 是否帶有可變參數
* invoke(Object obj, Object... args)調用方法
* getAnnotation(Class<T> annotationClass) 獲取註解信息
*/
三、示例
public class Test {
public void getClazz() {
//方式一:使用默認構造函數創建
try {
Class clazz = User.class;
User user = (User) clazz.newInstance();
Constructor constructor = clazz.getConstructor();
User user1 = (User) constructor.newInstance();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
//方式二:通過Constructor.newInstance創建
try {
Class clazz = User.class;
Constructor constructor = clazz.getDeclaredConstructor(String.class, String.class);
User user = (User) constructor.newInstance("", "");
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
Class clazz = Class.forName("com.lin.app.test.User");
Object obj = clazz.getDeclaredConstructor(String.class, String.class).newInstance("姓名", "地址");
Field address = clazz.getDeclaredField("address");
//設置允許訪問private對象
address.setAccessible(true);
//獲取address的值
print("before ", address.getName(), address.get(obj).toString());
//改變address的值
address.set(obj, "成都");
print("after ", address.getName(), address.get(obj).toString());
Method setMethod=clazz.getDeclaredMethod("setName",String.class);
//設置允許訪問private對象
setMethod.setAccessible(true);
Method getMethod=clazz.getDeclaredMethod("getName",String.class);
getMethod.setAccessible(true);
print("before",getMethod.getName(),((String)getMethod.invoke(obj)));
setMethod.invoke(obj,"張三");
print("after",getMethod.getName(),((String)getMethod.invoke(obj)));
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
private void print(String... msg) {
StringBuilder builder = new StringBuilder();
for (String s : msg) {
builder.append(s).append(" - ");
}
if (builder.length() > 0) {
builder.deleteCharAt(builder.length() - 2);
}
Log.e(getClass().getSimpleName(), builder.toString());
}
}
public class User {
private String name;
private String address;
public User() {
}
public User(String name, String address) {
this.name = name;
this.address = address;
}
private String getName() {
return name;
}
private void setName(String name) {
this.name = name;
}
}