Java反射機制學習1

Java 反射機制可以讓我們在編譯期(Compile Time)之外的運行期(Runtime)檢查類,接口,變量以及方法的信息。反射還可以讓我們在運行期實例化對象,調用方法,通過調用 get/set 方法獲取變量的值。

下面是一個 Java 反射的簡單例子:

import java.lang.reflect.Method;


public class MyObject {
    String name;
    String password;


    public MyObject(String name, String password) {
        super();
        this.name = name;
        this.password = password;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

    public static void main(String[] args) {
        Method[] methods = MyObject.class.getMethods();

        for(Method method : methods){
            System.out.println("method = " + method.getName());
        }
    }
}

在這個例子中通過調用 MyObject 類的 class 屬性獲取對應的 Class 類的對象,通過這個 Class 類的對象獲取 MyObject 類中的方法集合。迭代這個方法的集合並且打印每個方法的名字。
輸出結果:

method = main
method = getName
method = setName
method = getPassword
method = setPassword
method = wait
method = wait
method = wait
method = equals
method = toString
method = hashCode
method = getClass
method = notify
method = notifyAll

使用 Java 反射機制可以在運行時期檢查 Java 類的信息,檢查 Java 類的信息往往是你在使用 Java 反射機制的時候所做的第一件事情,通過獲取類的信息你可以獲取以下相關的內容:

Class 對象
類名
修飾符
包信息
父類
實現的接口
構造器
方法
變量
註解

Class 對象

在你想檢查一個類的信息之前,你首先需要獲取類的 Class 對象。Java 中的所有類型包括基本類型(int, long, float等等),即使是數組都有與之關聯的 Class 類的對象。如果你在編譯期知道一個類的名字的話,那麼你可以使用如下的方式獲取一個類的 Class 對象。

Class myObjectClass = MyObject.class;

如果你在編譯期不知道類的名字,但是你可以在運行期獲得到類名的字符串,那麼你則可以這麼做來獲取 Class 對象:

String className = ... ;//在運行期獲取的類名字符串
Class class = Class.forName(className);

在使用 Class.forName() 方法時,你必須提供一個類的全名,這個全名包括類所在的包的名字。例如 MyObject 類位於 com.jenkov.myapp 包,那麼他的全名就是 com.jenkov.myapp.MyObject。 如果在調用Class.forName()方法時,沒有在編譯路徑下(classpath)找到對應的類,那麼將會拋出ClassNotFoundException。

類名

你可以從 Class 對象中獲取兩個版本的類名。
通過 getName() 方法返回類的全限定類名(包含包名):

Class aClass = ... //獲取Class對象,具體方式可見Class對象小節
String className = aClass.getName();

如果你僅僅只是想獲取類的名字(不包含包名),那麼你可以使用 getSimpleName()方法:

Class aClass = ... //獲取Class對象,具體方式可見Class對象小節
String simpleClassName = aClass.getSimpleName();

修飾符

可以通過 Class 對象來訪問一個類的修飾符, 即public,private,static 等等的關鍵字,你可以使用如下方法來獲取類的修飾符:

Class  aClass = ... //獲取Class對象,具體方式可見Class對象小節
int modifiers = aClass.getModifiers();

修飾符都被包裝成一個int類型的數字,這樣每個修飾符都是一個位標識(flag bit),這個位標識可以設置和清除修飾符的類型。 可以使用 java.lang.reflect.Modifier 類中的方法來檢查修飾符的類型:

Modifier.isAbstract(int modifiers);
Modifier.isFinal(int modifiers);
Modifier.isInterface(int modifiers);
Modifier.isNative(int modifiers);
Modifier.isPrivate(int modifiers);
Modifier.isProtected(int modifiers);
Modifier.isPublic(int modifiers);
Modifier.isStatic(int modifiers);
Modifier.isStrict(int modifiers);
Modifier.isSynchronized(int modifiers);
Modifier.isTransient(int modifiers);
Modifier.isVolatile(int modifiers);

包信息

可以使用 Class 對象通過如下的方式獲取包信息:

Class  aClass = ... //獲取Class對象,具體方式可見Class對象小節
Package package = aClass.getPackage();

通過 Package 對象你可以獲取包的相關信息,比如包名,你也可以通過 Manifest 文件訪問位於編譯路徑下 jar 包的指定信息,比如你可以在 Manifest 文件中指定包的版本編號。

父類

通過 Class 對象你可以訪問類的父類,如下例:

Class superclass = aClass.getSuperclass();

可以看到 superclass 對象其實就是一個 Class 類的實例,所以你可以繼續在這個對象上進行反射操作。
實現的接口

可以通過如下方式獲取指定類所實現的接口集合:

Class  aClass = ... //獲取Class對象,具體方式可見Class對象小節
Class[] interfaces = aClass.getInterfaces();

由於一個類可以實現多個接口,因此 getInterfaces(); 方法返回一個 Class 數組,在 Java 中接口同樣有對應的 Class 對象。 注意:getInterfaces() 方法僅僅只返回當前類所實現的接口。當前類的父類如果實現了接口,這些接口是不會在返回的 Class 集合中的,儘管實際上當前類其實已經實現了父類接口。
構造器

你可以通過如下方式訪問一個類的構造方法:

Constructor[] constructors = aClass.getConstructors();

更多有關 Constructor 的信息可以訪問 Constructors。
方法

你可以通過如下方式訪問一個類的所有方法:

Method[] method = aClass.getMethods();

變量

你可以通過如下方式訪問一個類的成員變量:

Field[] method = aClass.getFields();

註解

你可以通過如下方式訪問一個類的註解:

Annotation[] annotations = aClass.getAnnotations();

示例:

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;


public class MyObject {
    String name;
    String password;


    public MyObject(String name, String password) {
        super();
        this.name = name;
        this.password = password;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }

    public static void main(String[] args) {
        Class myObject = MyObject.class;

        Method[] methods = myObject.getMethods();
        Field[] fields = myObject.getDeclaredFields();
        Constructor[] constructors = myObject.getDeclaredConstructors();

        System.out.println(myObject.getName());
        System.out.println(myObject.getPackage());
        System.out.println(myObject.getSuperclass());
        System.out.println(myObject.getSimpleName());
        System.out.println(myObject.getModifiers());
        for(Method method : methods){
            System.out.println("method = " + method.getName());
        }
        for(Field field : fields){
            System.out.println("field = " + field.getName());
        }
        for(Constructor constructor : constructors){
            System.out.println("constructor = " + constructor.getName());
        }
    }
}

輸出結果:

MyObject
null
class java.lang.Object
MyObject
1
method = main
method = getName
method = setName
method = getPassword
method = setPassword
method = wait
method = wait
method = wait
method = equals
method = toString
method = hashCode
method = getClass
method = notify
method = notifyAll
field = name
field = password
constructor = MyObject
發佈了20 篇原創文章 · 獲贊 9 · 訪問量 8萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章