首頁 > 軟體

Java框架設計靈魂之反射的範例詳解

2022-06-21 22:03:52

框架:半成品軟體。可以在框架的基礎上進行軟體開發,簡化編碼。

反射就是把Java類中的各個成員對映成一個個的Java物件。

即在執行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;

對於任意一個物件,都能呼叫它的任意一個方法和屬性。

這種動態獲取資訊及動態呼叫物件方法的功能叫Java的反射機制。

好處:

1. 可以在程式執行過程中,操作這些物件。

2. 可以解耦,提高程式的可延伸性。

獲取Class物件的方式

1. Class.forName("全類名"):將位元組碼檔案載入進記憶體,返回Class物件

多用於組態檔,將類名定義在組態檔中。讀取檔案,載入類。

2. 類名.class:通過類名的屬性class獲取

多用於引數的傳遞

3. 物件.getClass():getClass()方法在Object類中定義著。

多用於物件的獲取位元組碼的方式

//1.Class.forName("全類名")
Class cls1 = Class.forName("com.zjq.javabase.base25.domain.Person");
System.out.println(cls1);
//2.類名.class
Class cls2 = Person.class;
System.out.println(cls2);
//3.物件.getClass()
Person p = new Person();
Class cls3 = p.getClass();
System.out.println(cls3);

結論:

同一個位元組碼檔案(*.class)在一次程式執行過程中,只會被載入一次,不論通過哪一種方式獲取的Class物件都是同一個。

Class物件功能

測試的Person類:

package com.zjq.javabase.base25.domain;
 
/**
 * @author zjq
 */
public class Person {
    private String name;
    private int age;
 
    public String a;
    protected String b;
    String c;
    private String d;
 
 
    public Person() {
    }
 
    public Person(String name, int age) {
 
        this.name = name;
        this.age = age;
    }
 
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public int getAge() {
        return age;
    }
 
    public void setAge(int age) {
        this.age = age;
    }
 
    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + ''' +
                ", age=" + age +
                ", a='" + a + ''' +
                ", b='" + b + ''' +
                ", c='" + c + ''' +
                ", d='" + d + ''' +
                '}';
    }
 
 
    public void eat(){
        System.out.println("eat...");
    }
 
    public void eat(String food){
        System.out.println("eat..."+food);
    }
}

獲取成員變數們

Field[] getFields() :獲取所有public修飾的成員變數

Field getField(String name)   獲取指定名稱的 public修飾的成員變數

Field[] getDeclaredFields()  獲取所有的成員變數,不考慮許可權修飾符

Field getDeclaredField(String name)  

案例:

//0.獲取Person的Class物件
Class personClass = Person.class;
//1.Field[] getFields()獲取所有public修飾的成員變數
Field[] fields = personClass.getFields();
for (Field field : fields) {
    System.out.println(field);
}
 
System.out.println("------------");
//2.Field getField(String name)
Field a = personClass.getField("a");
//獲取成員變數a 的值
Person p = new Person();
Object value = a.get(p);
System.out.println(value);
//設定a的值
a.set(p,"張三");
System.out.println(p);
 
System.out.println("===================");
 
//Field[] getDeclaredFields():獲取所有的成員變數,不考慮修飾符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
    System.out.println(declaredField);
}
//Field getDeclaredField(String name)
Field d = personClass.getDeclaredField("d");
//忽略存取許可權修飾符的安全檢查
d.setAccessible(true);//暴力反射
Object value2 = d.get(p);
System.out.println(value2);

獲取構造方法們

Constructor<?>[] getConstructors()  

Constructor<T> getConstructor(類<?>... parameterTypes)  

Constructor<T> getDeclaredConstructor(類<?>... parameterTypes)  

Constructor<?>[] getDeclaredConstructors()  

案例:

//0.獲取Person的Class物件
Class personClass = Person.class;
 
//Constructor<T> getConstructor(類<?>... parameterTypes)
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//建立物件
Object person = constructor.newInstance("張三", 23);
System.out.println(person);
 
System.out.println("----------");
 
 
Constructor constructor1 = personClass.getConstructor();
System.out.println(constructor1);
//建立物件
Object person1 = constructor1.newInstance();
System.out.println(person1);
 
Object o = personClass.newInstance();
System.out.println(o);

獲取成員方法們

Method[] getMethods()  

Method getMethod(String name, 類<?>... parameterTypes)  

Method[] getDeclaredMethods()  

Method getDeclaredMethod(String name, 類<?>... parameterTypes)  

案例:

//0.獲取Person的Class物件
Class personClass = Person.class;
//獲取指定名稱的方法
Method eat_method = personClass.getMethod("eat");
Person p = new Person();
//執行方法
eat_method.invoke(p);
 
 
Method eat_method2 = personClass.getMethod("eat", String.class);
//執行方法
eat_method2.invoke(p,"飯");
 
System.out.println("-----------------");
 
//獲取所有public修飾的方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
    System.out.println(method);
    String name = method.getName();
    System.out.println(name);
    //method.setAccessible(true);
}
 
//獲取類名
String className = personClass.getName();
System.out.println(className);//com.zjq.javabase.base25.domain.Person

獲取全類名  

String getName()  

Field:成員變數

操作:

1. 設定值

void set(Object obj, Object value)  

2. 獲取值

get(Object obj) 

3. 忽略存取許可權修飾符的安全檢查

setAccessible(true):暴力反射

Constructor:構造方法

建立物件:

T newInstance(Object... initargs)  

如果使用空引數構造方法建立物件,操作可以簡化:Class物件的newInstance方法

Method:方法物件

執行方法:

Object invoke(Object obj, Object... args)  

獲取方法名稱:

String getName:獲取方法名

案例

需求:寫一個"框架",不能改變該類的任何程式碼的前提下,可以幫我們建立任意類的物件,並且執行其中任意方法

實現:

1. 組態檔

2. 反射

步驟:

1. 將需要建立的物件的全類名和需要執行的方法定義在組態檔中

2. 在程式中載入讀取組態檔

3. 使用反射技術來載入類檔案進記憶體

4. 建立物件

5. 執行方法

程式碼:

pro.properties檔案內容如下:

className=com.zjq.javabase.base25.domain.Student
methodName=sleep

Student類:

public class Student {
 
    public void sleep() {
        System.out.println("sleep...");
    }
}

反射操作:

//1.載入組態檔
//1.1建立Properties物件
Properties pro = new Properties();
//1.2載入組態檔,轉換為一個集合
//1.2.1獲取class目錄下的組態檔
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("pro.properties");
pro.load(is);
 
//2.獲取組態檔中定義的資料
String className = pro.getProperty("className");
String methodName = pro.getProperty("methodName");
 
 
//3.載入該類進記憶體
Class cls = Class.forName(className);
//4.建立物件
Object obj = cls.newInstance();
//5.獲取方法物件
Method method = cls.getMethod(methodName);
//6.執行方法
method.invoke(obj);

到此這篇關於Java框架設計靈魂之反射的範例詳解的文章就介紹到這了,更多相關Java反射內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com