概述
Java反射機制:在運行狀態中,能夠知道任意類的所有屬性和方法,能夠調用任意對象的所有屬性和方法
和"反"對應的就是"正",所謂的"正"就是指我們正常new出一個對象進行相應操作。那麼如果我們不知道要使用的類是什麼怎麼辦?比如JDBC中加載不同的數據庫驅動程序、Spring框架中注入各種Bean,同一個業務要操作很多不同的類,沒辦法把所有的對象new出來,這時候就要使用反射創建一個實例,然後再操作
常用操作
先寫一個類
public class Student {
@Getter
@Setter
private String name;
@Getter
@Setter
private int id;
public Student() {
System.out.println("無參構造器");
}
private Student(String name) {
this.name = name;
System.out.println("name:" + name);
}
public Student(String name, int id) {
this.name = name;
this.id = id;
System.out.println("name:" + name + "id" + id);
}
private void eat(String name) {
System.out.println(name + " eat chuanchuan");
}
public void study(){
System.out.println("study");
}
}
獲取Class對象
爲什麼要獲取Class對象呢?因爲所有的操作都是要先根據Class對象創建一個實例出來
-
使用Class.forName(“類全名”),因爲類可能不存在,所以會拋出ClassNotFoundException異常
Class c1 = Class.forName(“java.lang.String”);
-
通過類名.Class獲取,最安全、性能最高,只適合在編譯前就知道要操作的類名的場景
Class c1 = String.class
-
通過對象的getClass()獲取,適用於傳過來一個Object的對象,但是不知道具體是什麼類
String str = new String("Hello"); Class c3 = str.getClass();
創建對象
有兩種方法:
-
通過Class的newInstance()方法,只能使用無參構造方法
Class<?> studentClass = Student.class; Student student = (Student) studentClass.newInstance();
-
通過Constructor對象的newInstance()方法,可以選擇構造方法,但是不能選擇私有構造方法,否則會報NoSuchMethodException異常
Constructor<?> constructor1 = studentClass.getConstructor(); Constructor<?> constructor2 = studentClass.getConstructor(String.class); Student s1 = (Student) constructor1.newInstance(); Student s2 = (Student) constructor2.newInstance("zcs");
最後一行代碼會報錯,因爲Student(String name)是私有的,那麼如何獲取私有的呢?看一下常用API
方法名 作用 getConstructors() 獲取public構造方法 getDeclaredConstructors() 獲取所有構造方法 getConstructor(Class<?>…) 獲取指定參數的public構造方法 getDeclaredConstructor(Class<?>…) 獲取指定參數的構造方法(可以是private) 把Constructor換成Field和Method就是對屬性和方法的操作,區別就是返回值不同
例如Method method=class.getDeclaredMethod()
還有就是對於獲取私有類型的方法(帶Declraed的),需要設置setAccessible(true),具體見下文
// 私有構造方法
Constructor<?> constructor3 = studentClass.getDeclaredConstructor(String.class);
constructor3.setAccessible(true);
Student s3 = (Student) constructor3.newInstance("zcs");
// 私有屬性
Field name = studentClass.getDeclaredField("name");
name.setAccessible(true);
System.out.println(name.get(s3));
// 私有方法,第一個參數是方法名,第二個是參數類型
Method method = studentClass.getDeclaredMethod("eat",String.class);
method.setAccessible(true);
// 第一個參數是實例,第二個是具體參數
method.invoke(s3,"zcs");