反射的本質就是:在運行時,把 Java 類中的各種成分映射成一個個的 Java 對象。**
0.反射和類加載關係
類加載過程如下:
-
編譯,Java 編譯器將 .java 編譯產生 .class 二進制文件。
-
加載,JVM 中的類加載器解析.class 文件內的信息。
類加載器會根據類的全限定名來獲取此類的二進制字節流,生成代表這個類的 java.lang.Class 對象。
-
加載結束後,JVM 開始進行連接階段(包含驗證、準備、初始化)。經過這一系列操作,類的變量會被初始化。
-
初始化
反射就是上述第二步,**Java 中,無論生成某個類的多少個對象,這些對象都會對應於同一個 Class 對象。**使用反射可獲取class,然後進行各種操作。
- JVM 加載方法的時候,遇到 new User(),JVM 會根據 User 的全限定名去加載 User.class 。
- JVM 會去本地磁盤查找 User.class 文件並加載 JVM 內存中。
- JVM 通過調用類加載器自動創建這個類對應的 Class 對象,並且存儲在 JVM 的方法區。注意:一個類有且只有一個 Class 對象。
1.獲取Class對象的方法
3種:
-
forName
Class c1 = Class.forName("xxx.xxx.xxx");
-
通過類獲取Class
Class c2 = Boolean.class;
-
通過對象 getClass
Boolean bool = new Boolean(); Class c3 = bool.getClass();
2.獲取Class對象的信息
setAccessible() //是一個通用的方法,可獲取到對應信息的超級權限,若當前信息有private等權限控制,該方法可拿到操作權限
構造方法
-
獲取constructors數組
cla.getConstructors()
-
獲取constructor
getConstructor(Class<?>... parameterTypes)
-
獲取非public的構造函數
getDeclaredConstructor(Class<?>... parameterTypes)
使用對象創建實例方式見下
屬性
-
獲取屬性數組
getFields()
-
獲取指定Field
getField(String name)
-
獲取非public的屬性
getDeclaredField(String name)
-
設置屬性
set(Object,param)
方法
-
獲取方法數組
getMethods()
-
獲取指定數組
getMethod(String name, Class<?>... parameterTypes)
-
獲取非public數組
getDeclaredMethod(String name, Class<?>... parameterTypes)
-
指定對象調用方法
invoke(Object)
3.反射操作實例對象
判斷是否爲類的實例兩種方式:
- 用 instanceof 關鍵字
- 用 Class 對象的 isInstance 方法(它是一個 Native 方法)
ArrayList arrayList = new ArrayList();
Boolean isList1 = arrayList instanceof List
Boolean isList2 = List.class.isInstance(arrayList)
創建實例
- 用 Class 對象的 newInstance 方法,沒有無參構造函數無法創建,需使用第2種。
- 用 Constructor 對象的 newInstance 方法。
demo:
public class TestReObject {
private int id;
private String name;
public TestReObject(){
}
public TestReObject(int id,String name){
this.id = id;
this.name = name;
}
}
String classString = "reflect.TestReObject";
Class cla = Class.forName(classString);
TestReObject reObject = (TestReObject) cla.newInstance();
Constructor constructor = cla.getConstructor(int.class,String.class);
TestReObject str2 = (TestReObject) constructor.newInstance(12,"abc");
PS
demo
public class AboutReflect {
public static void main(String[] args) {
try {
//獲取class對象
Class cla = Class.forName("Base.ObjectTest");
//class對象創建實例對象方式一
ObjectTest objectTest = (ObjectTest) cla.newInstance();
//class對象創建實例對象方式二
Constructor constructor = cla.getConstructor(int.class, String.class);
ObjectTest objectTest1 = (ObjectTest) constructor.newInstance(12, "abc");
//獲取 constructor數組及指定constructor
Constructor[] constructors = cla.getConstructors();
Constructor constructor0 = cla.getConstructor();
Constructor constructor1 = cla.getConstructor(int.class,String.class);
//可以獲取非public的構造函數
Constructor constructor2 = cla.getDeclaredConstructor(int.class);
System.out.println(constructor2.getParameterCount());
for(Constructor cons:constructors){
System.out.println(cons.getParameterCount());
}
//獲取屬性
Field[] fields = cla.getFields();
System.out.println("field數量:"+fields.length);
//獲取屬性的註解,拿到超級權限,然後注入到指定對象
Field fieldId = cla.getDeclaredField("id");
fieldId.setAccessible(true);
fieldId.set(objectTest,fieldId.getAnnotation(TestAnnotation.class).id());
System.out.println(objectTest.toString());
//獲取方法 並使用指定對象訪問
Method method = cla.getDeclaredMethod("print",int.class,String.class);
method.invoke(objectTest,996,"icu");
} catch (Exception e) {
e.printStackTrace();
}
}
}
class ObjectTest {
@TestAnnotation(id=123)
private long id;
private String name;
public ObjectTest() {
}
public ObjectTest(int id, String name) {
this.id = id;
this.name = name;
}
protected ObjectTest(int id){
this.id = id;
}
public void print(int id,String name){
System.out.println(id+"==="+name);
}
@Override
public String toString() {
return "ObjectTest{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface TestAnnotation {
int id() default 1;
}