概述
反射機制是在運行時,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意個對象,都能夠調用它的任意一個方法。在java中,只要給定類的名字,就可以通過反射機制來獲得類的所有信息。反射是框架設計的靈魂,它功能很強大,我們學會了它就可以搭配很多東西一起使用,下面一起來學習使用反射吧!
使用Book類來練習反射,代碼如下:
public class Book {
private Integer id;
private String name;
public Integer age;
public Book() {
System.out.println("Public 無參構造函數");
}
public Book(String name) {
System.out.println("Public 帶參構造函數");
}
private Book(String name,Double price){
System.out.println("Private 帶兩參構造函數");
}
public void printAll(){
System.out.println("公開方法");
}
private void printOne(){
System.out.println("私有方法");
}
}
獲取類的三種方式
若想使用反射,必須先得到代表類的字節碼的Class對象,Class類用於表示.class文件(字節碼)。
第一種:使用Class.forName
使用 Class.forName(String classPath)時,請求參數classPath寫需要反射的類名,一般是以包名.類名。
try {
Class clz = Class.forName("com.entity.Book");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
第二種:使用類名.class
使用這種方法時,需要知道有這個類。
Class clz = Book.class;
第三種:對象.getClass()
使用的前提是對象已經被實例化。
Book book = new Book();
Class clz = book.getClass();
總結:這三種方法各有千秋,我們一般使用第一種方式,在開發中,請按照自己的實際需求去使用。
獲取構造函數
getDeclaredConstructors(); 獲取所有的構造函數
getDeclaredConstructor(參數類型); 獲取一個指定參數類型的構造函數
getConstructors(); 獲取所有公共的構造函數
getConstructor(參數類型); 獲取一個指定參數類型的、public修飾的構造函數
使用方法:
//獲取所有的構造函數
Constructor[] constructors = clz.getDeclaredConstructors();
//獲取單個所有的構造函數
try {
Constructor constructor =
clz.getDeclaredConstructor(String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
//獲取所有的公開構造函數
Constructor[] constructors1 = clz.getConstructors();
//獲取單個公開構造函數
try {
Constructor constructor = clz.getConstructor(String.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
獲取名字
返回類型:String,可以反射類名、方法名和構造函數名等等。
getName(); //獲取全名 例如:com.bean.Book
getSimpleName() //獲取類名 例如:Book
Class clz = Book.class;
String name1 = clz.getName();
String name2 = clz.getSimpleName();
獲取包
返回類型:Package
Package aPackage = clz.getPackage();
獲取接口
getInterfaces(),
返回類型:Class[] interfaces
Class[] interfaces = clz.getInterfaces();
獲取父類/超類
getSuperclass()
返回類型:Class superclass
Class superclass = clz.getSuperclass();
實例化對象
語法糖:newInstance(Object initargs)
第一種方式
Class clz = Book.class;
Object obj = clz.newInstance(); //將創建一個無參book對象
第二種方式
Class clz = Book.class;
Constructor constructor = clz.getDeclaredConstructor(); //獲得無參構造
Object obj = constructor.newInstance(); //實例化book對象
設置訪問屬性
clz.setAccessible(true) //可訪問
clz.setAccessible(false) //不可訪問
//默認是false
Field id = clz.getField("age"); //age字段
id.setAccessible(true); //設為可訪問
id.setAccessible(false); //設為不可訪問
獲取方法
- getMethods():獲取所有的公共方法,注意,它會將系統自帶的方法也得到
- getMethod(String name):獲取單個公共方法,由參數指定方法名
- getDeclaredMethods():獲取所有的方法,注意:它不會獲取系統自帶的方法
- getDeclaredMethod(String name):獲取單個的所有方法 參數是可指定方法名
Class clz = Class.forName("Book");
Method[] methods = clz.getMethods(); //獲取所有的公共方法
for (Method method : methods) {
System.out.println(method.getName());
}
Method method = clz.getMethod("printAll"); // 獲取單個公共方法
method.invoke(clz.newInstance(), null); // 調用方法
Method[] methods = clz.getDeclaredMethods(); //獲取所有方法
for (Method method1 : methods) {
System.out.println(method1.getName());
}
Method method1 = clz.getDeclaredMethod("printOne"); //獲取單個公共方法
System.out.println(method1.getName());
調用方法
method.invoke(Object obj,Object... args)
obj:如果是實例方法,則傳入該方法的類對象;如果是靜態方法,寫null。
args:方法的參數值,沒有寫null,或不寫都行
// 獲取單個的public方法,無法獲取private方法
Method method = clz.getMethod("printAll");
//使用方法
method.invoke(clz.newInstance(),null);
反射面試題
Q:Java反射創建對象效率高,還是new創建對象的效率高?
A: 通過new創建對象的效率比較高。通過反射時,先查找類資源,使用類加載器創建,過程比較繁瑣,所以效率較低。
Q:Java反射的作用是?
A: 反射機制是在運行時,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意個對象,都能夠調用它的任意一個方法。在java 中,只要給定類的名字,就可以通過反射機制來獲得類的所有信息。
Q:哪里會用到反射機制?
A: 加載MySQL的驅動類,如Hibernate、MyBatis等框架中會使用。動態代理設計模式也采用了反射機制。
例1:加載MySQL的驅動類,Class.forName('com.mysql.jdbc.Driver.class');
例2:使用反射機制,根據這個字符串獲得某個類的Class實例;
Q:反射機制的優缺點是?
A: 優點 能夠運行時動態獲取類的實例,提高靈活性;與動態編譯結合。可以解耦,提高程序的可擴展性。
缺點 使用反射性能較低,需要解析字節碼,將內存中的對象進行解析;相對不安全,破壞了封裝性(因為通過反射可以獲得私有方法和屬性)
提升性能解決方案:通過setAccessible(true),關閉JDK的安全檢查來提升反射速度。第一次反射后,會有緩存,下次反射會快很多。ReflflectASM工具類,通過字節碼生成的方式加快反射速度
結束語
對於Java反射,您怎么看?歡迎參與話題互動討論,分享你的觀點和看法, 評論區留言哦,喜歡小編文章的朋友請點贊,謝謝您的參與!
