面試官:五年經驗,我不問問反射說不過去吧?


1. 反射是什么?

反射是一種機制,是一種能力,是指JVM在運行過程中,對於任意一個類,都可以知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用他的任意方法和屬性

2. 反射的原理?

如果你對 JVM 的類加載機制有所了解(這里不了解也沒關系),就會知道,類在編譯的時候,會生成一個 .class 文件,當類被使用的時候,這個 class 文件就會被讀取並被載入到虛擬機中,生成對應類型的 Class 對象,這個被創建出的 Class 對象中就包含了我們原本的類中一切信息,通過這個對象,我們就可以去獲取這個類的屬性和方法,並且把這些屬性和方法轉換成一個對象,從而達到改變/執行的目的。

3. 反射的使用?

使用反射的第一步,是獲取一個 Class 對象,我們可以通過以下幾種方式去獲取一個 Class 對象

獲取 Class 對象

// 1. 根據類的全限定名
Class str1 = Class.forName("java.lang.String");

// 2. .class獲取
Class str2 = String.class;

// 3. 繼承自 Object 類的 getClass 方法
String s = new String();
Class str3 = s.getClass();

拿到了 Class 對象,下面我就可以對這個 Class 對象進行進一步的剖析,獲取它的構造方法,字段和一般方法

獲取Constructor,Method,Filed

在獲取之前,我們首先來新建個一個 Test 類來供我們使用

@Data
class Test {

    private String id;

    private String name;

    public String code;
}

這里需要⚠️注意,我在這里新建了兩個private的字段和一個public 的字段,是為了給大家展示,即使是反射,也無法獲取private的屬性~

// 獲取 constructor
Constructor[] constructors = test.getConstructors();
Arrays.stream(constructors).forEach(System.out::println);

System.out.println("------------------");

// 獲取 filed
Field[] fields = test.getFields();
Arrays.stream(fields).forEach(System.out::println);

System.out.println("------------------");

// 獲取 method
Method[] methods = test.getMethods();
Arrays.stream(methods).forEach(System.out::println);

打印的結果如下:

public show.shanhe.interview.reflection.Test()
------------------
public java.lang.String show.shanhe.interview.reflection.Test.code
------------------
public boolean show.shanhe.interview.reflection.Test.equals(java.lang.Object)
public java.lang.String show.shanhe.interview.reflection.Test.toString()
public int show.shanhe.interview.reflection.Test.hashCode()
public java.lang.String show.shanhe.interview.reflection.Test.getName()
public void show.shanhe.interview.reflection.Test.setName(java.lang.String)
public java.lang.String show.shanhe.interview.reflection.Test.getId()
public java.lang.String show.shanhe.interview.reflection.Test.getCode()
public void show.shanhe.interview.reflection.Test.setCode(java.lang.String)
public void show.shanhe.interview.reflection.Test.setId(java.lang.String)
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

Filed的打印中,我們可以看到只有code字段被打印了出來,其余兩個private的字段並沒有出現在我們打印的列表中。

拿到了方法,我們就可以用反射去執行方法

Method setName = test.getMethod("setName", String.class);
Test t = test.newInstance();
setName.invoke(t,"shanhe");
System.out.println(t.getName());

使用Methodinvoke方法,就可以去執行setName方法,這樣就可以達到給對象賦值的目的~

關於反射的使用方法,到這里就告一段落,下面我們來看一下在項目中,我們如何使用反射去達到我們的目的,完成自動化的操作。

4. 反射的實際應用場景

在我們的實際業務開發中,我們很少用到反射去實現我們的業務功能,因為在業務執行的過程中,我們使用反射會使代碼的執行效率變得很低,所以反射一般是應用在我們設計框架的時候去使用,我們平時使用到的一些框架和技術,其底層都是基於反射去實現的,簡而言之,反射是用來造輪子的,那么反射造的輪子,我們日常項目開發中經常用到的有哪些呢?

說起 Spring 的特性,大多數人腦海中浮現的的下面這兩個名字,其實這兩個特性都是基於反射去實現的。

AOP

基於我們對 AOP 的了解,我們不難知道(如果不知道,請等待設計模式之代理模式的文章),AOP是基於動態代理去實現對方法的增強處理,那么動態代理類一般都會去繼承InvocationHandler這個接口,然后通過重寫接口中的invoke方法,就可以實現AOP所要達到的目的。

IOC

IOC的實現,實際上就是通過工廠模式+反射來完成的,首先,我們通過注解或者xml的方式,將類(Bean)注冊到BeanFatory中,然后程序在執行的過程中,通過bean的全路徑名,使用反射去獲取一個對象實例

當然,這里沒有列舉出來的還有很多很多,比如文件的反編譯,比如java的agent機制,比如tomcat,比如動態生成類的框架,幾乎我們所能見到的框架中,都或多或少使用了反射這個神器來實現,反射的使用熟練程度,通常也是用來區分CRUD程序員和造輪子程序員的最大區別,也是進階路上必不可少的一道坎兒,掌握了反射,我們就可以有更多的思路去實現,去優化我們的代碼~

學會使用反射+設計模式這是一個成長的標志,所以,如果你有學到,請給我點贊+關注,這是給一個堅持原創的人最大的支持和鼓勵,另外設計模式系列博客預熱中,敬請期待~


免責聲明!

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



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