JDK源碼分析 反射

說明

對于JDK源碼分析的文章,僅僅記錄我認為重要的地方。源碼的細節實在太多,不可能面面俱到地寫清每個邏輯。所以我的JDK源碼分析,著重在JDK的體系架構層面,具體源碼可以參考:http://www.cnblogs.com/skywang12345/category/455711.html

反射簡介

在運行狀態中,我們可以根據“類的部分已知的信息”來還原“類的全部的信息”。

類的部分已知的信息:

  • 類名
  • 類的對象

類的全部信息

  • 屬性
  • 方法
  • 繼承關系
  • Annotation注解

根據類名構造類

代碼示例

User類

public class User implements Serializable{
    private static final long serialVersionUID = 1510634274152200118L;
    
    private int id;
    private String passWord;
    
    public User() {
        System.out.println("Create user... ");
    }
    
    public User(int id, String passWord) {
        this.id = id;
        this.passWord = passWord;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public String getPassWord() {
        return passWord;
    }
    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
    @Override
    public String toString() {
        return "User [id=" + id + ", passWord=" + passWord + "]";
    }
}

根據類名,構造類的代碼:

@Test
public void testReflection() throws Exception {
    Class<?> clazz = Class.forName("test.User");
    User user = (User) clazz.newInstance();
    System.out.println("user = " + user);
}

輸出:

Create user... 
user = User [id=0, passWord=null]

獲取 class 對象

@Test
public void testClazz() throws Exception {
    Class<?> clazz1 = Class.forName("test.User");
    Class clazz2 = User.class;
    Class clazz3 = new User().getClass();
    System.out.println("clazz1: " + clazz1);
    System.out.println("clazz2: " + clazz2);
    System.out.println("clazz3: " + clazz3);
}

輸出:

Create user... 
clazz1: class test.User
clazz2: class test.User
clazz3: class test.User

class 的 API

  • 構造函數
  • 成員方法
  • 成員變量
  • 類的其它信息(如注解、包名、類名、繼承關系等等)

構造函數

// 獲取“參數是parameterTypes”的public的構造函數
public Constructor    getConstructor(Class[] parameterTypes)
// 獲取全部的public的構造函數
public Constructor[]    getConstructors()
// 獲取“參數是parameterTypes”的,并且是類自身聲明的構造函數,包含public、protected和private方法。
public Constructor    getDeclaredConstructor(Class[] parameterTypes)
// 獲取類自身聲明的全部的構造函數,包含public、protected和private方法。
public Constructor[]    getDeclaredConstructors()
// 如果這個類是“其它類的構造函數中的內部類”,調用getEnclosingConstructor()就是這個類所在的構造函數;若不存在,返回null。
public Constructor    getEnclosingConstructor()

測試:

@Test
public void testConstructor() throws Exception {
    Class<?> clazz = Class.forName("test.User");
    Constructor<?> constructor = clazz.getDeclaredConstructor(null);
    Object object1 = constructor.newInstance();
    System.out.println(object1);
    
    Constructor<?> constructor2 = clazz.getDeclaredConstructor(new Class[] {int.class, String.class});
    Object object2 = constructor2.newInstance(1, "123456");
    System.out.println(object2);
}

輸出:

Create user... 
User [id=0, passWord=null]
User [id=1, passWord=123456]

可以調用默認的構造函數,也可以通過

clazz.getDeclaredConstructor(new Class[] {int.class, String.class})

來調用User的含參構造函數

public User(int id, String passWord) {
    this.id = id;
    this.passWord = passWord;
}

成員方法

// 獲取“名稱是name,參數是parameterTypes”的public的函數(包括從基類繼承的、從接口實現的所有public函數)
public Method    getMethod(String name, Class[] parameterTypes)
// 獲取全部的public的函數(包括從基類繼承的、從接口實現的所有public函數)
public Method[]    getMethods()
// 獲取“名稱是name,參數是parameterTypes”,并且是類自身聲明的函數,包含public、protected和private方法。
public Method    getDeclaredMethod(String name, Class[] parameterTypes)
// 獲取全部的類自身聲明的函數,包含public、protected和private方法。
public Method[]    getDeclaredMethods()
// 如果這個類是“其它類中某個方法的內部類”,調用getEnclosingMethod()就是這個類所在的方法;若不存在,返回null。
public Method    getEnclosingMethod()

可以判斷類中是否含有某個方法,也可以調用類中的任何一個方法(包括私有方法)。

@Test
public void testMethod() throws Exception {
    Class<?> clazz = Class.forName("test.User");
    
    Method[] declaredMethods = clazz.getDeclaredMethods();
    for (Method method : declaredMethods) {
        System.out.println(method);
    }
    System.out.println();
    
    Method printInfo = clazz.getDeclaredMethod("printInfo", new Class[]{});
    User user = (User) clazz.newInstance();
    printInfo.invoke(user, null);
}

輸出:

Create user... 
public java.lang.String test.User.toString()
public int test.User.getId()
public void test.User.printInfo()
public void test.User.setId(int)
public void test.User.setPassWord(java.lang.String)
public java.lang.String test.User.getPassWord()
User [id=0, passWord=null]

成員變量

// 獲取“名稱是name”的public的成員變量(包括從基類繼承的、從接口實現的所有public成員變量)
public Field    getField(String name)
// 獲取全部的public成員變量(包括從基類繼承的、從接口實現的所有public成員變量)
public Field[]    getFields()
// 獲取“名稱是name”,并且是類自身聲明的成員變量,包含public、protected和private成員變量。
public Field    getDeclaredField(String name)
// 獲取全部的類自身聲明的成員變量,包含public、protected和private成員變量。
public Field[]    getDeclaredFields()
@Test
public void testField() throws Exception {
    Class<?> clazz = Class.forName("test.User");
    
    Field[] fields = clazz.getDeclaredFields();
    for (Field field : fields) {
        System.out.println(field);
    }
    
    // 創建并通過反射,修改一個 private 變量 id
    User user = (User) clazz.newInstance();
    Field field = clazz.getDeclaredField("id");
    field.setAccessible(true);
    field.set(user, 123);
    user.printInfo();
}

輸出:

private static final long test.User.serialVersionUID
private int test.User.id
private java.lang.String test.User.passWord
Create user... 
User [id=123, passWord=null]

我們可以看到,User中對于id的定義:

private int id;

而在測試用例中,可以獲取對象中私有的id變量,并直接修改內容,最終輸出的id=123。

類的其它信息

注解

// 獲取類的"annotationClass"類型的注解 (包括從基類繼承的、從接口實現的所有public成員變量)
public Annotation<A>    getAnnotation(Class annotationClass)
// 獲取類的全部注解 (包括從基類繼承的、從接口實現的所有public成員變量)
public Annotation[]    getAnnotations()
// 獲取類自身聲明的全部注解 (包含public、protected和private成員變量)
public Annotation[]    getDeclaredAnnotations()

“父類”和“接口”相關的API

// 獲取實現的全部接口
public Type[]    getGenericInterfaces()
// 獲取父類
public Type    getGenericSuperclass()
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容