反射 Reflection

十四2001發表於2024-07-07

反射 Reflection

靜態語言和動態語言

動態語言

  • 是一類在執行時可以改變其結構的語言:例如新的函式、物件、甚至程式碼可以被引進,已有的函式可以被刪除或是其他結構上的變化。通俗點說就是在執行時,程式碼可以根據某些條件改變自身結構。
  • 主要動態語言:Object-C、C#、JavaScript、PHP、Python等。

靜態語言

  • 與動態語言相對應的,執行時結構不可變的語言就是靜態語言。如Java、C、C++
  • Java不是動態語言,但Java可以稱之為“準動態語言”。即Java有一定的動態性,我們可以利用反射機制獲得類似動態語言的特性。Java的動態性讓程式設計的時候更加靈活!

Java Reflection

  • Reflection(反射)是Java被視為動態語言的關鍵,反射機制允許程式在執行期藉助於Reflection API取得任何類的內部資訊,並能直接操作任意物件的內部屬性及方法。

    Class c = Class.forName("java.lang.String")
    
  • 載入完類之後,在堆記憶體的方法區中就產生了一個Class型別的物件(一個類只有一個Class物件),這個物件就包含了完整的類的結構資訊。我們可以透過這個物件看到類的結構。這個物件就像一面鏡子,透過這個鏡子看到類的結構,所以,我們形象的稱之為:反射

實體類:pojo,entity 只有一些屬性的類

package OOP.reflection;

/**
 * @version: java version 1.8
 * @Author: 14
 */
public class Test01 {
    public static void main(String[] args) throws ClassNotFoundException {
        //透過反射獲取類的class物件
        Class c1 = Class.forName("OOP.reflection.User");
        System.out.println(c1);
        Class c2 = Class.forName("OOP.reflection.User");
        Class c3 = Class.forName("OOP.reflection.User");
        Class c4 = Class.forName("OOP.reflection.User");

        System.out.println(c2.hashCode());
        System.out.println(c3.hashCode());
        System.out.println(c4.hashCode());
    }
}
//實體類
class User{
    int id;
    String name;
    int age;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    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;
    }
}

Class類

物件照鏡子後可以得到的資訊:某個類的屬性、方法和構造器、某個類到底實現了哪些介面。對於每個類而言,JRE都為其保留一個不變的Class型別的物件。
一個Class物件包含了特定某個結構(class/interface/enum/annotation/primitive type/void/)的有關資訊。

  • Class本身也是一個類
  • Class物件只能由系統建立物件
  • 一個載入的類在JVM中只會有一個Class例項
  • 一個Class物件對應的是一個載入到JVM中的一個.class檔案>每個類的例項都會記得自己是由哪個Class 例項所生成透過Class可以完整地得到一個類中的所有被載入的結構
  • Class類是Reflection的根源,針對任何你想動態載入、執行的類,唯有先獲得相應的Class物件

在Object類中定義了以下的方法,此方法被所有子類繼承

public final Class getClass()

以上的方法返回值的型別是一個Class類,此類是Java反射的源頭,實際上所謂反射從程式的執行結果來看也很好理解,即:可以透過物件反射求出類的名稱。

Class類的常用方法

方法名 功能說明
static ClassforName(Srting name) 返回指定類名name的Class物件
Object newInstance() 呼叫預設建構函式,返回Class物件的一個例項
getName() 返回此Class物件所表示的實體(類、介面、陣列類或void)的名稱
Class getSuperClass() 返回當前Class物件的父類的Class物件
Class[] getinterfaces() 獲取當前Class物件的介面
ClassLoader getClassLoader() 返回該類的類載入器
Constructor[]getConstructors() 返回一個包含某些Constructor物件的陣列
Method getMothed(String name,Class.. T) 返回一個Method物件,此物件的形參型別為paramType
Field[]getDeclaredFields() 返回Field物件的一個陣列

獲取Class類的幾種方式

  • 若已知具體的類,透過類的class屬性獲取,該方法最為安全可靠,程式效能最高。

    Class clazz= Person.class;
    
  • 已知某個類的例項,呼叫該例項的getClass()方法獲取Class物件

    Class clazz = person.getClass();
    
  • 已知一個類的全類名,且該類在類路徑下,可透過Class類的靜態方法forName()獲取,可能丟擲ClassNotFoundException

    Class clazz= Class.forName("demo01.Student");
    
  • 內建基本資料型別可以直接用類名.Type

    Class clazz = Integer.TYPE;
    
  • ClassLoader

package OOP.reflection;

/**
 * @version: java version 1.8
 * @Author: 14
 */
public class Test02 {
    public static void main(String[] args) throws ClassNotFoundException {
        Person person = new Student();
        System.out.println(person);
        //方式一:透過物件獲得
        Class c1 = person.getClass();
        System.out.println(c1.hashCode());
        //方式二:forname獲得
        Class c2 = Class.forName("OOP.reflection.Student");
        System.out.println(c2.hashCode());
        //方式三:透過類名.class獲得
        Class c3 = Student.class;
        System.out.println(c3.hashCode());
        //方法四:基本內建型別的包裝類都有一個Type屬性
        Class c4 = Integer.TYPE;
        System.out.println(c4);
		//獲取父類
        Class c5 = c2.getSuperclass();
        System.out.println(c5);
    }
}
class Person{
    String name;
    public Person(){
    }
    public Person(String name){
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                '}';
    }
}
class Student extends Person{
    public Student(){
        this.name = "Student";
    }
}
class Teacher extends Person{
    public Teacher(){
        this.name = "Teacher";
    }
}

相關文章