溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java反射機制詳解_動力節(jié)點Java學(xué)院整理

發(fā)布時間:2020-09-05 19:20:31 來源:腳本之家 閱讀:110 作者:mrr 欄目:編程語言

Java 反射機制介紹

Java 反射機制。通俗來講呢,就是在運行狀態(tài)中,我們可以根據(jù)“類的部分已經(jīng)的信息”來還原“類的全部的信息”。這里“類的部分已經(jīng)的信息”,可以是“類名”或“類的對象”等信息?!邦惖娜啃畔ⅰ本褪侵浮邦惖膶傩?,方法,繼承關(guān)系和Annotation注解”等內(nèi)容。

舉個簡單的例子:假設(shè)對于類ReflectionTest.java,我們知道的唯一信息是它的類名是“com.bjpowernode.Reflection”。這時,我們想要知道ReflectionTest.java的其它信息(比如它的構(gòu)造函數(shù),它的成員變量等等),要怎么辦呢?

這就需要用到“反射”。通過反射,我們可以解析出ReflectionTest.java的完整信息,包括它的構(gòu)造函數(shù),成員變量,繼承關(guān)系等等。

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

這個過程主要分為兩步:

第1步:根據(jù)“類名”來獲取對應(yīng)類的Class對象。

第2步:通過Class對象的函數(shù)接口,來讀取“類的構(gòu)造函數(shù),成員變量”等信息。

下面,我們根據(jù)示例來加深對這個概念的理解。示例如下(Demo1.java):

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

運行結(jié)果:

create Person
cls=class com.bjpowernode.test.Person

說明:

(01) Person類的完整包名是"com.bjpowernode.test.Person"。而 Class.forName("com.bjpowernode.test.Person"); 這一句的作用是,就是根據(jù)Person的包名來獲取Person的Class對象。

(02) 接著,我們調(diào)用Class對象的newInstance()方法,創(chuàng)建Person對象。

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

Class 詳細(xì)說明

1 獲取Class對象的方法

我這里總結(jié)了4種常用的“獲取Class對象”的方法:

方法1:Class.forName("類名字符串") (注意:類名字符串必須是全稱,包名+類名)

方法2:類名.class

方法3:實例對象.getClass()

方法4:"類名字符串".getClass()

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

package com.bjpowernode.test;
import java.lang.Class;
public class Demo2 {
  public static void main(String[] args) {
    try {
      // 方法1:Class.forName("類名字符串") (注意:類名字符串必須是全稱,包名+類名)
      //Class cls1 = Class.forName("com.bjpowernode.test.Person");
      Class<?> cls1 = Class.forName("com.bjpowernode.test.Person");
      //Class<Person> cls1 = Class.forName("com.bjpowernode.test.Person");
      // 方法2:類名.class
      Class cls2 = Person.class; 
      // 方法3:實例對象.getClass()
      Person person = new Person();
      Class cls3 = person.getClass();
      // 方法4:"類名字符串".getClass()
      String str = "com.bjpowernode.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");
  }
}

運行結(jié)果:

create Person
cls1=class com.bjpowernode.test.Person, cls2=class com.bjpowernode.test.Person, cls3=class com.bjpowernode.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()

我們根據(jù)類的特性,將Class中的類分為4部分進行說明:構(gòu)造函數(shù),成員方法,成員變量,類的其它信息(如注解、包名、類名、繼承關(guān)系等等)。

2.1 構(gòu)造函數(shù)

“構(gòu)造函數(shù)”相關(guān)API

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

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

package com.bjpowernode.test;
import java.lang.Class;
import java.lang.reflect.Constructor;
/**
 * java Class類的Constructor相關(guān)API的測試函數(shù)
 *
 * 
 */
public class DemoClassContructor {
  public static void main(String[] args) {
    // getDeclaredConstructor() 的測試函數(shù)
    testGetDeclaredConstructor() ;
    // getConstructor() 的測試函數(shù)
    testGetConstructor() ;
    // getEnclosingConstructor() 的測試函數(shù)
    testGetEnclosingConstructor() ;
  }
  /**
   * getDeclaredConstructor() 的測試函數(shù)
   */
  public static void testGetDeclaredConstructor() {
    try {
      // 獲取Person類的Class
      Class<?> cls = Class.forName("com.bjpowernode.test.Person");
      // 根據(jù)class,獲取構(gòu)造函數(shù)
      Constructor cst1 = cls.getDeclaredConstructor();
      Constructor cst2 = cls.getDeclaredConstructor(new Class[]{String.class});
      Constructor cst3 = cls.getDeclaredConstructor(new Class[]{String.class, int.class, Gender.class});
      // 根據(jù)構(gòu)造函數(shù),創(chuàng)建相應(yīng)的對象
      cst1.setAccessible(true); // 因為Person中Person()是private的,所以這里要設(shè)置為可訪問
      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() 的測試函數(shù)
   */
  public static void testGetConstructor() {
    try {
      // 獲取Person類的Class
      Class<?> cls = Class.forName("com.bjpowernode.test.Person");
      // 根據(jù)class,獲取構(gòu)造函數(shù)
      //Constructor cst1 = cls.getConstructor(); // 拋出異常,因為默認(rèn)構(gòu)造函數(shù)是private權(quán)限。
      //Constructor cst2 = cls.getConstructor(new Class[]{String.class});// 拋出異常,因為該構(gòu)造函數(shù)是protected權(quán)限。
      Constructor cst3 = cls.getConstructor(new Class[]{String.class, int.class, Gender.class});
      // 根據(jù)構(gòu)造函數(shù),創(chuàng)建相應(yīng)的對象
      //Object p1 = cst1.newInstance();
      //cst1.setAccessible(true); // 因為Person中Person()是private的,所以這里要設(shè)置為可訪問
      //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() 的測試函數(shù)
   */
  public static void testGetEnclosingConstructor() {
    try {
      // 獲取Person類的Class
      Class<?> cls = Class.forName("com.bjpowernode.test.Person");
      // 根據(jù)class,調(diào)用Person類中有內(nèi)部類InnerA的構(gòu)造函數(shù)
      Constructor cst = cls.getDeclaredConstructor(new Class[]{String.class, int.class});
      // 根據(jù)構(gòu)造函數(shù),創(chuàng)建相應(yīng)的對象
      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;
    //內(nèi)部類在構(gòu)造方法中
    class InnerA{
    }
    // 獲取InnerA的Class對象
    Class cls = InnerA.class;

    // 獲取“封閉該內(nèi)部類(InnerA)”的構(gòu)造方法
    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()的參數(shù)必須是,Person類的完整包名。
運行結(jié)果:

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.bjpowernode.test.Person(java.lang.String,int)
getEnclosingConstructor() : obj=(Ammy, 18, FEMALE)

說明:

(01) 首先,要搞清楚Person類,它是我們自定義的類。專門用來測試這些API的。Person中有一個成員變量gender;它是Gender對象,Gender是一個枚舉類。取值可以是MALE或者FEMALE。

(02) testGetDeclaredConstructor() 是“getDeclaredConstructor() 的測試函數(shù)”。getDeclaredConstructor()可以“獲取類中任意的構(gòu)造函數(shù),包含public、protected和private方法”。

(03) testGetConstructor() 是“getConstructor() 的測試函數(shù)”。getConstructor()只能“獲取類中public的構(gòu)造函數(shù)”。

(04) testGetEnclosingConstructor() 是“getEnclosingConstructor() 的測試函數(shù)”。關(guān)于getEnclosingConstructor()的介紹,官方說法是“如果該 Class 對象表示構(gòu)造方法中的一個本地或匿名類,則返回 Constructor 對象,它表示底層類的立即封閉構(gòu)造方法。否則返回 null?!?通俗點來說,就是“如果一個類A的構(gòu)造函數(shù)中定義了一個內(nèi)部類InnerA,則通過InnerA的Class對象調(diào)用getEnclosingConstructor()方法,可以獲取類A的這個構(gòu)造函數(shù)”。

2.2 成員方法

 “成員方法”相關(guān)API

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

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

package com.bjpowernode.test;
import java.lang.Class;
import java.lang.reflect.Method;
/**
 * java Class類的Method相關(guān)API的測試函數(shù)
 *
 * 
 */
public class DemoClassMethod {
  public static void main(String[] args) {
      // getDeclaredMethod() 的測試函數(shù)
      testGetDeclaredMethod() ;
      // getMethod() 的測試函數(shù)
      testGetMethod() ;
      // getEnclosingMethod() 的測試函數(shù)
      testGetEnclosingMethod() ;
  }
  /**
   * getDeclaredMethod() 的測試函數(shù)
   */
  public static void testGetDeclaredMethod() {
    try {
      // 獲取Person類的Class
      Class<?> cls = Class.forName("com.bjpowernode.test.Person");
      // 根據(jù)class,調(diào)用類的默認(rèn)構(gòu)造函數(shù)(不帶參數(shù))
      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[]{});
      // 調(diào)用獲取的方法
      mSetName.invoke(person, new Object[]{"Jimmy"});
      mSetAge.invoke(person, new Object[]{30});
      mSetGender.setAccessible(true);  // 因為Person中setGender()是private的,所以這里要設(shè)置為可訪問
      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中g(shù)etGender()是private的,所以這里要設(shè)置為可訪問
      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() 的測試函數(shù)
   */
  public static void testGetMethod() {
    try {
      // 獲取Person類的Class
      Class<?> cls = Class.forName("com.bjpowernode.test.Person");
      // 根據(jù)class,調(diào)用類的默認(rèn)構(gòu)造函數(shù)(不帶參數(shù))
      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權(quán)限。
      //Method mGetAge = cls.getMethod("getAge", new Class[]{});         // 拋出異常,因為getAge()是protected權(quán)限。
      //Method mSetGender = cls.getMethod("setGender", new Class[]{Gender.class}); // 拋出異常,因為setGender()是private權(quán)限。
      //Method mGetGender = cls.getMethod("getGender", new Class[]{});       // 拋出異常,因為getGender()是private權(quán)限。
      // 調(diào)用獲取的方法
      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() 的測試函數(shù)
   */
  public static void testGetEnclosingMethod() {
    try {
      // 獲取Person類的Class
      Class<?> cls = Class.forName("com.bjpowernode.test.Person");
      // 根據(jù)class,調(diào)用類的默認(rèn)構(gòu)造函數(shù)(不帶參數(shù))
      Object person = cls.newInstance();
      // 根據(jù)class,調(diào)用Person類中有內(nèi)部類InnerB的函數(shù)
      Method mGetInner = cls.getDeclaredMethod("getInner", new Class[]{});
      // 根據(jù)構(gòu)造函數(shù),創(chuàng)建相應(yīng)的對象
      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;
  }
  // 獲取”姓名“。權(quán)限是 public
  public String getName() {
    return name;
  }
  // 設(shè)置”姓名“。權(quán)限是 public
  public void setName(String name) {
    this.name = name;
  }
  // 獲取”年齡“。權(quán)限是 protected
  protected int getAge() {
    return age;
  }
  // 設(shè)置”年齡“。權(quán)限是 protected
  protected void setAge(int age) {
    this.age = age;
  }
  // 獲取“性別”。權(quán)限是 private
  private Gender getGender() {
    return gender;
  }
  // 設(shè)置“性別”。權(quán)限是 private
  private void setGender(Gender gender) {
    this.gender = gender;
  }
  // getInner() 中有內(nèi)部類InnerB,用來測試getEnclosingMethod()
  public void getInner() {
    // 內(nèi)部類
    class InnerB{
    }
    // 獲取InnerB的Class對象
    Class cls = InnerB.class;
    // 獲取“封閉該內(nèi)部類(InnerB)”的構(gòu)造方法
    Method cst = cls.getEnclosingMethod();
    System.out.println("call--\"getInner()\" cst="+cst);
  }
  @Override
  public String toString() {
    return "("+name+", "+age+", "+gender+")";
  }
}

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

運行結(jié)果:

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

2.3 成員變量

“成員變量”的相關(guān)API

// 獲取“名稱是name”的public的成員變量(包括從基類繼承的、從接口實現(xiàn)的所有public成員變量)
public Field  getField(String name)
// 獲取全部的public成員變量(包括從基類繼承的、從接口實現(xiàn)的所有public成員變量)
public Field[]  getFields()
// 獲取“名稱是name”,并且是類自身聲明的成員變量,包含public、protected和private成員變量。
public Field  getDeclaredField(String name)
// 獲取全部的類自身聲明的成員變量,包含public、protected和private成員變量。
public Field[]  getDeclaredFields()
接下來,我們通過示例對這些API進行說明。示例代碼(DemoClassField.java)如下:
package com.bjpowernode.test;
import java.lang.Class;
import java.lang.reflect.Field;
/**
 * java Class類的"成員變量"相關(guān)API的測試函數(shù)
 *
 * 
 */
public class DemoClassField {
  public static void main(String[] args) {
    // getDeclaredField() 的測試函數(shù)
    testGetDeclaredField() ;
    // getField() 的測試函數(shù)
    testGetField() ;
  }
  /**
   * getDeclaredField() 的測試函數(shù)
   * getDeclaredField() 用于獲取的是類自身聲明的所有成員遍歷,包含public、protected和private方法。
   */
  public static void testGetDeclaredField() {
    try {
      // 獲取Person類的Class
      Class<?> cls = Class.forName("com.bjpowernode.test.Person");
      // 根據(jù)class,調(diào)用類的默認(rèn)構(gòu)造函數(shù)(不帶參數(shù))
      Object person = cls.newInstance();
      // 根據(jù)class,獲取Filed
      Field fName = cls.getDeclaredField("name");
      Field fAge = cls.getDeclaredField("age");
      Field fGender = cls.getDeclaredField("gender");
      // 根據(jù)構(gòu)造函數(shù),創(chuàng)建相應(yīng)的對象
      fName.set(person, "Hamier");
      fAge.set(person, 31);
      fGender.setAccessible(true); // 因為"flag"是private權(quán)限,所以要設(shè)置訪問權(quán)限為true;否則,會拋出異常。
      fGender.set(person, Gender.FEMALE);
      System.out.printf("%-30s: person=%s\n", 
          "getDeclaredField()", person);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
  /**
   * getField() 的測試函數(shù)
   * getField() 用于獲取的是public的“成員”
   */
  public static void testGetField() {
    try {
      // 獲取Person類的Class
      Class<?> cls = Class.forName("com.bjpowernode.test.Person");
      // 根據(jù)class,調(diào)用類的默認(rèn)構(gòu)造函數(shù)(不帶參數(shù))
      Object person = cls.newInstance();
      // 根據(jù)class,獲取Filed
      Field fName = cls.getField("name");
      Field fAge = cls.getDeclaredField("age");    // 拋出異常,因為Person中age是protected權(quán)限。 
      Field fGender = cls.getDeclaredField("gender"); // 拋出異常,因為Person中g(shù)ender是private權(quán)限。 
      // 根據(jù)構(gòu)造函數(shù),創(chuàng)建相應(yīng)的對象
      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()的參數(shù)必須是,Person類的完整包名。

運行結(jié)果:

getDeclaredField() : person=(Hamier, 31, FEMALE)
getField() : person=(Grace, 0, FEMALE)

2.4 類的其它信息

2.4.1 “注解”相關(guān)的API

// 獲取類的"annotationClass"類型的注解 (包括從基類繼承的、從接口實現(xiàn)的所有public成員變量)
public Annotation<A>  getAnnotation(Class annotationClass)
// 獲取類的全部注解 (包括從基類繼承的、從接口實現(xiàn)的所有public成員變量)
public Annotation[]  getAnnotations()
// 獲取類自身聲明的全部注解 (包含public、protected和private成員變量)
public Annotation[]  getDeclaredAnnotations()
接下來,我們通過示例對這些API進行說明。示例代碼(DemoClassAnnotation.java)如下:
package com.bjpowernode.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 {
      // 根據(jù)“類名”獲取 對應(yīng)的Class對象
      Class<?> cls = Class.forName("com.bjpowernode.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()的參數(shù)必須是,Person類的完整包名。

運行結(jié)果:

myann=@com.bjpowernode.test.MyAnnotation()

說明:

(01) MyAnnotation 是我們自定義個一個Annotation注解。若讀者不明白“注解”,可以參考博文“”TODO

(02) getAnnotation()就是獲取這個類的注解。

1.1.1.1

2.4.2 “父類”和“接口”相關(guān)的API

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

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

package com.bjpowernode.test;
import java.io.Serializable;
import java.lang.Runnable;
import java.lang.Thread;
import java.lang.Class;
import java.lang.reflect.Type;
/**
 * java Class類的有關(guān)父類和接口的測試
 */
public class DemoClassInterface {
  public static void main(String[] args) {
    try {
      // 根據(jù)“類名”獲取 對應(yīng)的Class對象
      Class<?> cls = Class.forName("com.bjpowernode.test.Person");
      // 獲取“Person”的父類
      Type father = cls.getGenericSuperclass();
      // 獲取“Person”實現(xiàn)的全部接口
      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,并且實現(xiàn)了Serializable和Runnable接口
 */
class Person extends Object implements Serializable, Runnable{
  @Override
  public void run() {
  }
}

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

運行結(jié)果:

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()
// 類是不是“本地類”。本地類,就是定義在方法內(nèi)部的類。
public boolean  isLocalClass()
// 類是不是“成員類”。成員類,是內(nèi)部類的一種,但是它不是“內(nèi)部類”或“匿名類”。
public boolean  isMemberClass()
// 類是不是“基本類型”。 基本類型,包括void和boolean、byte、char、short、int、long、float 和 double這幾種類型。
public boolean  isPrimitive()
// 類是不是“復(fù)合類”。 JVM中才會產(chǎn)生復(fù)合類,在java應(yīng)用程序中不存在“復(fù)合類”!
public boolean  isSynthetic()

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

package com.bjpowernode.test;
import java.lang.Class;
import java.lang.Runnable;
import java.lang.annotation.ElementType;
import java.util.TreeMap;
/**
 * java Class類的getName(), isInterface()等測試程序
 *
 * 
 */
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());
    // 類是不是“本地類”。本地類,就是定義在方法內(nèi)部的類。
    Class localCls = LocalA.class;
    System.out.printf("%-50s:isLocalClass()=%s\n", 
        localCls, localCls.isLocalClass());
    // 類是不是“成員類”。成員類,是內(nèi)部類的一種,但是它不是“內(nèi)部類”或“匿名類”。
    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());
    // 類是不是“復(fù)合類”。 JVM中才會產(chǎn)生復(fù)合類,在java應(yīng)用程序中不存在“復(fù)合類”!
    Class synCls = DemoClassOtherAPIs.class;
    System.out.printf("%-50s:isSynthetic()=%s\n", 
        synCls, synCls.isSynthetic());
  }
  // 內(nèi)部成員類
  class MemberB {
  }
}

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

運行結(jié)果:

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

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

以上所述是小編給大家介紹的Java反射機制詳解_動力節(jié)點Java學(xué)院整理,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復(fù)大家的。在此也非常感謝大家對億速云網(wǎng)站的支持!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI