程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Java反射機制:包括組成、結構和示例說明等內容

Java反射機制:包括組成、結構和示例說明等內容

編輯:關於JAVA

第1部分 Java 反射機制介紹

Java 反射機制。通俗來講呢,就是在運行狀態中,我們可以根據“類的部分已經的信息”來還原“類的全部的信息”。這裡“類的部分已經的信息”,可以是“類名”或“類的對象”等信息。“類的全部信息”就是指“類的屬性,方法,繼承關系和Annotation注解”等內容。

舉個簡單的例子:假設對於類ReflectionTest.java,我們知道的唯一信息是它的類名是“com.skywang.Reflection”。這時,我們想要知道ReflectionTest.java的其它信息(比如它的構造函數,它的成員變量等等),要怎麼辦呢?
這就需要用到“反射”。通過反射,我們可以解析出ReflectionTest.java的完整信息,包括它的構造函數,成員變量,繼承關系等等。

在了解了“java 反射機制”的概念之後,接下來思考一個問題:如何根據類的類名,來獲取類的完整信息呢?

這個過程主要分為兩步:
第1步:根據“類名”來獲取對應類的Class對象。
第2步:通過Class對象的函數接口,來讀取“類的構造函數,成員變量”等信息。
下面,我們根據示例來加深對這個概念的理解。示例如下(Demo1.java):

package com.skywang.test;
     
import java.lang.Class;
     
public class Demo1 {
     
    public static void main(String[] args) {
     
        try {
            // 根據“類名”獲取 對應的Class對象
            Class<?> cls = Class.forName("com.skywang.test.Person");
     
            // 新建對象。newInstance()會調用類不帶參數的構造函數
            Object obj = cls.newInstance();
     
            System.out.println("cls="+cls);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
     
class Person {
    public Person() {
        System.out.println("create Person");
    }
}

運行結果:
create Person
cls=class com.skywang.test.Person

說明:
(01) Person類的完整包名是"com.skywang.test.Person"。而 Class.forName("com.skywang.test.Person"); 這一句的作用是,就是根據Person的包名來獲取Person的Class對象。
(02) 接著,我們調用Class對象的newInstance()方法,創建Person對象。

現在,我們知道了“java反射機制”的概念以及它的原理。有了這個總體思想之後,接下來,我們可以開始對反射進行深入研究了。

第2部分 Class 詳細說明

1 獲取Class對象的方法

我這裡總結了4種常用的“獲取Class對象”的方法:
方法1:Class.forName("類名字符串") (注意:類名字符串必須是全稱,包名+類名)
方法2:類名.class
方法3:實例對象.getClass()
方法4:"類名字符串".getClass()

下面,我們通過示例演示這4種方法。示例如下(Demo2.java):

package com.skywang.test;
     
import java.lang.Class;
     
public class Demo2 {
     
    public static void main(String[] args) {
     
        try {
            // 方法1:Class.forName("類名字符串")  (注意:類名字符串必須是全稱,包名+類名)
            //Class cls1 = Class.forName("com.skywang.test.Person");
            Class<?> cls1 = Class.forName("com.skywang.test.Person");
            //Class<Person> cls1 = Class.forName("com.skywang.test.Person");
     
            // 方法2:類名.class
            Class cls2 = Person.class; 
     
            // 方法3:實例對象.getClass()
            Person person = new Person();
            Class cls3 = person.getClass();
     
            // 方法4:"類名字符串".getClass()
            String str = "com.skywang.test.Person"; 
            Class cls4 = str.getClass();
     
            System.out.printf("cls1=%s, cls2=%s, cls3=%s, cls4=%s\n", cls1, cls2, cls3, cls4);
     
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
     
class Person {
    public Person() {
        System.out.println("create Person");
    }
}

運行結果:

create Person
cls1=class com.skywang.test.Person, cls2=class com.skywang.test.Person, cls3=class com.skywang.test.Person, cls4=class java.lang.String

2 Class的API說明

Class的全部API如下表:

Class的全部API如下表:
public static Class    forName(String className)
public static Class    forName(String name, boolean initialize, ClassLoader loader)
public Constructor    getConstructor(Class[] parameterTypes)
public Constructor[]    getConstructors()
public Constructor    getDeclaredConstructor(Class[] parameterTypes)
public Constructor[]    getDeclaredConstructors()
public Constructor    getEnclosingConstructor()
public Method    getMethod(String name, Class[] parameterTypes)
public Method[]    getMethods()
public Method    getDeclaredMethod(String name, Class[] parameterTypes)
public Method[]    getDeclaredMethods()
public Method    getEnclosingMethod()
public Field    getField(String name)
public Field[]    getFields()
public Field    getDeclaredField(String name)
public Field[]    getDeclaredFields()
public Type[]    getGenericInterfaces()
public Type    getGenericSuperclass()
public Annotation<A>    getAnnotation(Class annotationClass)
public Annotation[]    getAnnotations()
public Annotation[]    getDeclaredAnnotations()
public boolean    isAnnotation()
public boolean    isAnnotationPresent(Class annotationClass)
public boolean    isAnonymousClass()
public boolean    isArray()
public boolean    isAssignableFrom(Class cls)
public boolean    desiredAssertionStatus()
public Class<U>    asSubclass(Class clazz)
public Class    getSuperclass()
public Class    getComponentType()
public Class    getDeclaringClass()
public Class    getEnclosingClass()
public Class[]    getClasses()
public Class[]    getDeclaredClasses()
public Class[]    getInterfaces()
public boolean    isEnum()
public boolean    isInstance(Object obj)
public boolean    isInterface()
public boolean    isLocalClass()
public boolean    isMemberClass()
public boolean    isPrimitive()
public boolean    isSynthetic()
public String    getSimpleName()
public String    getName()
public String    getCanonicalName()
public String    toString()
public ClassLoader    getClassLoader()
public Package    getPackage()
public int    getModifiers()
public ProtectionDomain    getProtectionDomain()
public URL    getResource(String name)
public InputStream    getResourceAsStream(String name)
public Object    cast(Object obj)
public Object    newInstance()
public Object[]    getSigners()
public Object[]    getEnumConstants()
public TypeVariable[]    getTypeParameters()

我們根據類的特性,將Class中的類分為4部分進行說明:構造函數,成員方法,成員變量,類的其它信息(如注解、包名、類名、繼承關系等等)。Class中涉及到Annotation(注解)的相關API,可以點擊查看前一章節關於Annotation的詳細介紹。

2.1 構造函數

“構造函數”相關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()

接下來,我們通過示例對這些API進行說明。示例代碼(DemoClassContructor.java)如下:

package com.skywang.test;
     
import java.lang.Class;
import java.lang.reflect.Constructor;
     
/**
 * java Class類的Constructor相關API的測試函數
 *
 * @author skywang
 */
public class DemoClassContructor {
     
    public static void main(String[] args) {
     
        // getDeclaredConstructor() 的測試函數
        testGetDeclaredConstructor() ;
     
        // getConstructor() 的測試函數
        testGetConstructor() ;
     
        // getEnclosingConstructor() 的測試函數
        testGetEnclosingConstructor() ;
    }
     
    /**
     * getDeclaredConstructor() 的測試函數
     */
    public static void testGetDeclaredConstructor() {
        try {
            // 獲取Person類的Class
            Class<?> cls = Class.forName("com.skywang.test.Person");
     
            // 根據class,獲取構造函數
            Constructor cst1 = cls.getDeclaredConstructor();
            Constructor cst2 = cls.getDeclaredConstructor(new Class[]{String.class});
            Constructor cst3 = cls.getDeclaredConstructor(new Class[]{String.class, int.class, Gender.class});
     
            // 根據構造函數,創建相應的對象
            cst1.setAccessible(true); // 因為Person中Person()是private的,所以這裡要設置為可訪問
            Object p1 = cst1.newInstance();
            Object p2 = cst2.newInstance("Juce");
            Object p3 = cst3.newInstance("Jody", 34, Gender.MALE);
     
            System.out.printf("%-30s: p1=%s, p2=%s, p3=%s\n", 
                    "getConstructor()", p1, p2, p3);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
     
    /**
     * getConstructor() 的測試函數
     */
    public static void testGetConstructor() {
        try {
            // 獲取Person類的Class
            Class<?> cls = Class.forName("com.skywang.test.Person");
     
            // 根據class,獲取構造函數
            //Constructor cst1 = cls.getConstructor(); // 拋出異常,因為默認構造函數是private權限。
            //Constructor cst2 = cls.getConstructor(new Class[]{String.class});// 拋出異常,因為該構造函數是protected權限。
            Constructor cst3 = cls.getConstructor(new Class[]{String.class, int.class, Gender.class});
     
            // 根據構造函數,創建相應的對象
            //Object p1 = cst1.newInstance();
            //cst1.setAccessible(true); // 因為Person中Person()是private的,所以這裡要設置為可訪問
            //Object p1 = cst1.newInstance();
            //Object p2 = cst2.newInstance("Kim");
            Object p3 = cst3.newInstance("Katter", 36, Gender.MALE);
     
            System.out.printf("%-30s: p3=%s\n", 
                    "getConstructor()", p3);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
    /**
     * getEnclosingConstructor() 的測試函數
     */
    public static void testGetEnclosingConstructor() {
        try {
            // 獲取Person類的Class
            Class<?> cls = Class.forName("com.skywang.test.Person");
     
            // 根據class,調用Person類中有內部類InnerA的構造函數
            Constructor cst = cls.getDeclaredConstructor(new Class[]{String.class, int.class});
     
            // 根據構造函數,創建相應的對象
            Object obj = cst.newInstance("Ammy", 18);
     
            System.out.printf("%-30s: obj=%s\n", 
                    "getEnclosingConstructor()", obj);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
     
     
// 枚舉類型。表示“性別”
enum Gender{  
    MALE, FEMALE
} 
// 人
class Person {
    private Gender gender;  // 性別
    private int age;        // 年齡
    private String name;    // 姓名
     
    private Person() {
        this.name = "unknown";
        this.age = 0;
        this.gender = Gender.FEMALE;
        System.out.println("call--\"private Person()\"");
    }
    protected Person(String name) {
        this.name = name;
        this.age = 0;
        this.gender = Gender.FEMALE;
        System.out.println("call--\"protected Person(String name)\"");
    }
    public Person(String name, int age, Gender gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
        System.out.println("call--\"public Person(String name, int age, Gender gender)\"");
    }
     
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
        this.gender = Gender.FEMALE;
        //內部類在構造方法中
        class InnerA{
        }
        // 獲取InnerA的Class對象
        Class cls = InnerA.class;
     
        // 獲取“封閉該內部類(InnerA)”的構造方法
        Constructor cst = cls.getEnclosingConstructor();
             
        System.out.println("call--\"public Person(String name, int age)\" cst="+cst);
    }
    @Override
    public String toString() {
        return "("+name+", "+age+", "+gender+")";
    }
}

注意:若程序無法運行,請檢查“forName()”中的包名是否正確!forName()的參數必須是,Person類的完整包名。

運行結果:
call--"private Person()"
call--"protected Person(String name)"
call--"public Person(String name, int age, Gender gender)"
getConstructor() : p1=(unknown, 0, FEMALE), p2=(Juce, 0, FEMALE), p3=(Jody, 34, MALE)
call--"public Person(String name, int age, Gender gender)"
getConstructor() : p3=(Katter, 36, MALE)
call--"public Person(String name, int age)" cst=public com.skywang.test.Person(java.lang.String,int)
getEnclosingConstructor() : obj=(Ammy, 18, FEMALE)

說明:
(01) 首先,要搞清楚Person類,它是我們自定義的類。專門用來測試這些API的。Person中有一個成員變量gender;它是Gender對象,Gender是一個枚舉類。取值可以是MALE或者FEMALE。
(02) testGetDeclaredConstructor() 是“getDeclaredConstructor() 的測試函數”。getDeclaredConstructor()可以“獲取類中任意的構造函數,包含public、protected和private方法”。
(03) testGetConstructor() 是“getConstructor() 的測試函數”。getConstructor()只能“獲取類中public的構造函數”。
(04) testGetEnclosingConstructor() 是“getEnclosingConstructor() 的測試函數”。關於getEnclosingConstructor()的介紹,官方說法是“如果該 Class 對象表示構造方法中的一個本地或匿名類,則返回 Constructor 對象,它表示底層類的立即封閉構造方法。否則返回 null。” 通俗點來說,就是“如果一個類A的構造函數中定義了一個內部類InnerA,則通過InnerA的Class對象調用getEnclosingConstructor()方法,可以獲取類A的這個構造函數”。

2.2 成員方法

“成員方法”相關API

// 獲取“名稱是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()

接下來,我們通過示例對這些API進行說明。示例代碼(DemoClassMethod.java)如下:

package com.skywang.test;
     
import java.lang.Class;
import java.lang.reflect.Method;
     
/**
 * java Class類的Method相關API的測試函數
 *
 * @author skywang
 */
public class DemoClassMethod {
     
    public static void main(String[] args) {
     
            // getDeclaredMethod() 的測試函數
            testGetDeclaredMethod() ;
     
            // getMethod() 的測試函數
            testGetMethod() ;
     
            // getEnclosingMethod() 的測試函數
            testGetEnclosingMethod() ;
    }
     
    /**
     * getDeclaredMethod() 的測試函數
     */
    public static void testGetDeclaredMethod() {
        try {
            // 獲取Person類的Class
            Class<?> cls = Class.forName("com.skywang.test.Person");
            // 根據class,調用類的默認構造函數(不帶參數)
            Object person = cls.newInstance();
     
            // 獲取Person中的方法
            Method mSetName = cls.getDeclaredMethod("setName", new Class[]{String.class});
            Method mGetName = cls.getDeclaredMethod("getName", new Class[]{});
            Method mSetAge  = cls.getDeclaredMethod("setAge", new Class[]{int.class});
            Method mGetAge  = cls.getDeclaredMethod("getAge", new Class[]{});
            Method mSetGender = cls.getDeclaredMethod("setGender", new Class[]{Gender.class});
            Method mGetGender = cls.getDeclaredMethod("getGender", new Class[]{});
     
            // 調用獲取的方法
            mSetName.invoke(person, new Object[]{"Jimmy"});
            mSetAge.invoke(person, new Object[]{30});
            mSetGender.setAccessible(true);    // 因為Person中setGender()是private的,所以這裡要設置為可訪問
            mSetGender.invoke(person, new Object[]{Gender.MALE});
            String name = (String)mGetName.invoke(person, new Object[]{});
            Integer age = (Integer)mGetAge.invoke(person, new Object[]{});
            mGetGender.setAccessible(true);    // 因為Person中getGender()是private的,所以這裡要設置為可訪問
            Gender gender = (Gender)mGetGender.invoke(person, new Object[]{});
     
            // 打印輸出
            System.out.printf("%-30s: person=%s, name=%s, age=%s, gender=%s\n", 
                    "getDeclaredMethod()", person, name, age, gender);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
     
    /**
     * getMethod() 的測試函數
     */
    public static void testGetMethod() {
        try {
            // 獲取Person類的Class
            Class<?> cls = Class.forName("com.skywang.test.Person");
            // 根據class,調用類的默認構造函數(不帶參數)
            Object person = cls.newInstance();
     
            // 獲取Person中的方法
            Method mSetName = cls.getMethod("setName", new Class[]{String.class});
            Method mGetName = cls.getMethod("getName", new Class[]{});
            //Method mSetAge  = cls.getMethod("setAge", new Class[]{int.class});         // 拋出異常,因為setAge()是protected權限。
            //Method mGetAge  = cls.getMethod("getAge", new Class[]{});                  // 拋出異常,因為getAge()是protected權限。
            //Method mSetGender = cls.getMethod("setGender", new Class[]{Gender.class}); // 拋出異常,因為setGender()是private權限。
            //Method mGetGender = cls.getMethod("getGender", new Class[]{});             // 拋出異常,因為getGender()是private權限。
     
            // 調用獲取的方法
            mSetName.invoke(person, new Object[]{"Phobe"});
            //mSetAge.invoke(person, new Object[]{38});
            //mSetGender.invoke(person, new Object[]{Gender.FEMALE});
            String name = (String)mGetName.invoke(person, new Object[]{});
            //Integer age = (Integer)mGetAge.invoke(person, new Object[]{});
            //Gender gender = (Gender)mGetGender.invoke(person, new Object[]{});
     
            // 打印輸出
            System.out.printf("%-30s: person=%s\n", 
                    "getMethod()", person);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
     
    /**
     * getEnclosingMethod() 的測試函數
     */
    public static void testGetEnclosingMethod() {
        try {
            // 獲取Person類的Class
            Class<?> cls = Class.forName("com.skywang.test.Person");
            // 根據class,調用類的默認構造函數(不帶參數)
            Object person = cls.newInstance();
     
            // 根據class,調用Person類中有內部類InnerB的函數
            Method mGetInner = cls.getDeclaredMethod("getInner", new Class[]{});
     
            // 根據構造函數,創建相應的對象
            mGetInner.invoke(person, new Object[]{});
     
            System.out.printf("%-30s: person=%s\n",
                       "getEnclosingMethod", person);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
     
}
     
enum Gender{  
    MALE, FEMALE
} 
class Person {
    private Gender gender;  // 性別
    private int age;        // 年齡
    private String name;    // 姓名
     
    public Person() {
        this("unknown", 0, Gender.FEMALE);
    }
    public Person(String name, int age, Gender gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
     
    // 獲取”姓名“。權限是 public
    public String getName() {
        return name;
    }
    // 設置”姓名“。權限是 public
    public void setName(String name) {
        this.name = name;
    }
    // 獲取”年齡“。權限是 protected
    protected int getAge() {
        return age;
    }
    // 設置”年齡“。權限是 protected
    protected void setAge(int age) {
        this.age = age;
    }
    // 獲取“性別”。權限是 private
    private Gender getGender() {
        return gender;
    }
    // 設置“性別”。權限是 private
    private void setGender(Gender gender) {
        this.gender = gender;
    }
     
     
    // getInner() 中有內部類InnerB,用來測試getEnclosingMethod()
    public void getInner() {
        // 內部類
        class InnerB{
        }
        // 獲取InnerB的Class對象
        Class cls = InnerB.class;
     
        // 獲取“封閉該內部類(InnerB)”的構造方法
        Method cst = cls.getEnclosingMethod();
             
        System.out.println("call--\"getInner()\" cst="+cst);
    }
     
     
    @Override
    public String toString() {
        return "("+name+", "+age+", "+gender+")";
    }
}

注意:若程序無法運行,請檢查“forName()”中的包名是否正確!forName()的參數必須是,Person類的完整包名。

運行結果:
getDeclaredMethod() : person=(Jimmy, 30, MALE), name=Jimmy, age=30, gender=MALE
getMethod() : person=(Phobe, 0, FEMALE)
call--"getInner()" cst=public void com.skywang.test.Person.getInner()
getEnclosingMethod : person=(unknown, 0, FEMALE)

2.3 成員變量

“成員變量”的相關API

// 獲取“名稱是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()

接下來,我們通過示例對這些API進行說明。示例代碼(DemoClassField.java)如下:

package com.skywang.test;
     
import java.lang.Class;
import java.lang.reflect.Field;
     
/**
 * java Class類的"成員變量"相關API的測試函數
 *
 * @author skywang
 */
public class DemoClassField {
     
    public static void main(String[] args) {
        // getDeclaredField() 的測試函數
        testGetDeclaredField() ;
     
        // getField() 的測試函數
        testGetField() ;
    }
     
    /**
     * getDeclaredField() 的測試函數
     * getDeclaredField() 用於獲取的是類自身聲明的所有成員遍歷,包含public、protected和private方法。
     */
    public static void testGetDeclaredField() {
        try {
            // 獲取Person類的Class
            Class<?> cls = Class.forName("com.skywang.test.Person");
            // 根據class,調用類的默認構造函數(不帶參數)
            Object person = cls.newInstance();
     
            // 根據class,獲取Filed
            Field fName = cls.getDeclaredField("name");
            Field fAge = cls.getDeclaredField("age");
            Field fGender = cls.getDeclaredField("gender");
     
            // 根據構造函數,創建相應的對象
            fName.set(person, "Hamier");
            fAge.set(person, 31);
            fGender.setAccessible(true);  // 因為"flag"是private權限,所以要設置訪問權限為true;否則,會拋出異常。
            fGender.set(person, Gender.FEMALE);
     
            System.out.printf("%-30s: person=%s\n", 
                    "getDeclaredField()", person);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
     
    /**
     * getField() 的測試函數
     * getField() 用於獲取的是public的“成員”
     */
    public static void testGetField() {
        try {
            // 獲取Person類的Class
            Class<?> cls = Class.forName("com.skywang.test.Person");
            // 根據class,調用類的默認構造函數(不帶參數)
            Object person = cls.newInstance();
     
            // 根據class,獲取Filed
            Field fName = cls.getField("name");
            Field fAge = cls.getDeclaredField("age");       // 拋出異常,因為Person中age是protected權限。 
            Field fGender = cls.getDeclaredField("gender"); // 拋出異常,因為Person中gender是private權限。 
     
            // 根據構造函數,創建相應的對象
            fName.set(person, "Grace");
            //fAge.set(person, 26);
            //fGender.set(person, Gender.FEMALE);
     
            System.out.printf("%-30s: person=%s\n", 
                    "getField()", person);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
     
     
// 枚舉類型。表示“性別”
enum Gender{  
    MALE, FEMALE
} 
// 人
class Person {
    // private。性別
    private Gender gender;
    // protected。 年齡
    protected int age;
    // public。 姓名
    public String name;
     
    public Person() {
        this("unknown", 0, Gender.FEMALE);
    }
     
    public Person(String name, int age, Gender gender) {
        this.name = name;
        this.age = age;
        this.gender = gender;
    }
     
    @Override
    public String toString() {
        return "("+name+", "+age+", "+gender+")";
    }
}

注意:若程序無法運行,請檢查“forName()”中的包名是否正確!forName()的參數必須是,Person類的完整包名。

運行結果:
getDeclaredField() : person=(Hamier, 31, FEMALE)
getField() : person=(Grace, 0, FEMALE)

2.4 類的其它信息

2.4.1 “注解”相關的API

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

接下來,我們通過示例對這些API進行說明。示例代碼(DemoClassAnnotation.java)如下:

package com.skywang.test;
     
import java.lang.Class;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
     
/**
 * java Class類getAnnotation()的測試程序
 */
public class DemoClassAnnotation {
     
    public static void main(String[] args) {
        try {
            // 根據“類名”獲取 對應的Class對象
            Class<?> cls = Class.forName("com.skywang.test.Person");
     
            // 獲取“Person類”的注解
            MyAnnotation myann = cls.getAnnotation(MyAnnotation.class);
     
            System.out.println("myann="+myann);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
     
/**
 * MyAnnotation是自定義個一個Annotation
 */
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation {
}
     
/**
 * MyAnnotation 是Person的注解。
 */
@MyAnnotation
class Person {
}

注意:若程序無法運行,請檢查“forName()”中的包名是否正確!forName()的參數必須是,Person類的完整包名。

運行結果:
[email protected]()

說明:
(01) MyAnnotation 是我們自定義個一個Annotation注解。若讀者不明白“注解”,可以參考博文“”TODO
(02) getAnnotation()就是獲取這個類的注解。

查看本欄目

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

// 獲取實現的全部接口
public Type[]    getGenericInterfaces()
// 獲取父類
public Type    getGenericSuperclass()

示例代碼(DemoClassInterface.java)如下:

package com.skywang.test;
     
import java.io.Serializable;
import java.lang.Runnable;
import java.lang.Thread;
import java.lang.Class;
import java.lang.reflect.Type;
     
/**
 * java Class類的有關父類和接口的測試
 */
public class DemoClassInterface {
     
    public static void main(String[] args) {
     
        try {
            // 根據“類名”獲取 對應的Class對象
            Class<?> cls = Class.forName("com.skywang.test.Person");
     
            // 獲取“Person”的父類
            Type father = cls.getGenericSuperclass();
            // 獲取“Person”實現的全部接口
            Type[] intfs = cls.getGenericInterfaces();
     
            System.out.println("father="+father);
            for (Type t:intfs)
                System.out.println("t="+t);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
     
/**
 * Person 繼承於 Object,並且實現了Serializable和Runnable接口
 */
class Person extends Object implements Serializable, Runnable{
     
    @Override
    public void run() {
    }
     
}

注意:若程序無法運行,請檢查“forName()”中的包名是否正確!forName()的參數必須是,Person類的完整包名。

運行結果:
father=class java.lang.Object
t=interface java.io.Serializable
t=interface java.lang.Runnable

2.4.3 剩余的API

// 獲取“類名”
public String    getSimpleName()
// 獲取“完整類名”
public String    getName()
// 類是不是“枚舉類”
public boolean    isEnum()
// obj是不是類的對象
public boolean    isInstance(Object obj)
// 類是不是“接口”
public boolean    isInterface()
// 類是不是“本地類”。本地類,就是定義在方法內部的類。
public boolean    isLocalClass()
// 類是不是“成員類”。成員類,是內部類的一種,但是它不是“內部類”或“匿名類”。
public boolean    isMemberClass()
// 類是不是“基本類型”。 基本類型,包括void和boolean、byte、char、short、int、long、float 和 double這幾種類型。
public boolean    isPrimitive()
// 類是不是“復合類”。 JVM中才會產生復合類,在java應用程序中不存在“復合類”!
public boolean    isSynthetic()

示例代碼(DemoClassOtherAPIs.java)如下:

package com.skywang.test;
     
import java.lang.Class;
import java.lang.Runnable;
import java.lang.annotation.ElementType;
import java.util.TreeMap;
     
/**
 * java Class類的getName(), isInterface()等測試程序
 *
 * @author skywang
 */
public class DemoClassOtherAPIs {
    public static void main(String[] args) {
     
        Class cls = DemoClassOtherAPIs.class;
        // 獲取“類名”
        System.out.printf("%-50s:getSimpleName()=%s\n", cls, cls.getSimpleName());
        // 獲取“完整類名”
        System.out.printf("%-50s:getName()=%s\n", cls, cls.getName());
     
        // 測試其它的API
        testOtherAPIs() ;
    }
     
    public static void testOtherAPIs() {
        // 本地類
        class LocalA {
        }
     
        // 測試枚舉類型。ElementType是一個枚舉類
        Class elementtypeCls = ElementType.class;
        System.out.printf("%-50s:isEnum()=%s\n", 
                elementtypeCls, elementtypeCls.isEnum());
     
        // 判斷是不是類的對象
        Class demoCls = DemoClassOtherAPIs.class;
        DemoClassOtherAPIs demoObj = new DemoClassOtherAPIs();
        System.out.printf("%-50s:isInstance(obj)=%s\n", 
                demoCls, demoCls.isInstance(demoObj));
     
        // 類是不是“接口”
        Class runCls = Runnable.class;
        System.out.printf("%-50s:isInterface()=%s\n", 
                runCls, runCls.isInterface());
     
        // 類是不是“本地類”。本地類,就是定義在方法內部的類。
        Class localCls = LocalA.class;
        System.out.printf("%-50s:isLocalClass()=%s\n", 
                localCls, localCls.isLocalClass());
     
        // 類是不是“成員類”。成員類,是內部類的一種,但是它不是“內部類”或“匿名類”。
        Class memCls = MemberB.class;
        System.out.printf("%-50s:isMemberClass()=%s\n", 
                memCls, memCls.isMemberClass());
     
        // 類是不是“基本類型”。 基本類型,包括void和boolean、byte、char、short、int、long、float 和 double這幾種類型。
        Class primCls = int.class;
        System.out.printf("%-50s:isPrimitive()=%s\n", 
                primCls, primCls.isPrimitive());
     
        // 類是不是“復合類”。 JVM中才會產生復合類,在java應用程序中不存在“復合類”!
        Class synCls = DemoClassOtherAPIs.class;
        System.out.printf("%-50s:isSynthetic()=%s\n", 
                synCls, synCls.isSynthetic());
    }
     
    // 內部成員類
    class MemberB {
    }
}

注意:若程序無法運行,請檢查“forName()”中的包名是否正確!forName()的參數必須是,Person類的完整包名。

運行結果:
class com.skywang.test.DemoClassOtherAPIs :getSimpleName()=DemoClassOtherAPIs
class com.skywang.test.DemoClassOtherAPIs :getName()=com.skywang.test.DemoClassOtherAPIs
class java.lang.annotation.ElementType :isEnum()=true
class com.skywang.test.DemoClassOtherAPIs :isInstance(obj)=true
interface java.lang.Runnable :isInterface()=true
class com.skywang.test.DemoClassOtherAPIs$1LocalA :isLocalClass()=true
class com.skywang.test.DemoClassOtherAPIs$MemberB :isMemberClass()=true
int :isPrimitive()=true
class com.skywang.test.DemoClassOtherAPIs :isSynthetic()=false

說明:isSynthetic()是用來判斷Class是不是“復合類”。這在java應用程序中只會返回false,不會返回true。因為,JVM中才會產生復合類,在java應用程序中不存在“復合類”!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved