轉|java反射方法和使用詳解


概述

  反射機制是在運行時,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意個對象,都能夠調用它的任意一個方法。在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反射,您怎么看?歡迎參與話題互動討論,分享你的觀點和看法, 評論區留言哦,喜歡小編文章的朋友請點贊,謝謝您的參與!

Reference

[1] https://www.cnblogs.com/liweixml/p/11462813.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM