【Java基礎知識】Java反射--Class、Constructor、Filed、Method類的使用

Windsor90發表於2017-01-22

1、反射概念

是程式可以訪問、檢測和修改它本身狀態或行為的一種能力。Java中的反射,能夠建立靈活的程式碼,這些程式碼可在執行時裝配,無需在元件之間進行原始碼連結。簡單的說就是:通過class檔案物件,去使用該檔案中的成員變數,構造方法,成員方法。每個類都有一個Class物件,每當編寫並且編譯了一個新類,就會產生一個Class物件【被儲存在一個同名的.class檔案中】所有的類都是在對其第一次使用的時候,動態載入到JVM中。Class物件僅在需要的時候才被載入,static初始化是在類載入時進行的。一旦某個類的Class物件被載入記憶體,它就被用來建立這個類的所有物件。Class類與java.lang.reflect類庫一起對反射的概念進行了支援,該類包含了Filed,Method,Constructor類,這些型別的物件由JVM在執行時建立,用以表示未知類裡對應的成員。這樣就可以使用Constructor建立新的物件,使用它get( ), set( )方法讀取和修改與Field物件關聯的欄位,用invoke( )方法呼叫Method物件關聯的方法。另外,還可以呼叫getFields()、getMethods( )和getConstructor( )等方法,以返回表示欄位、方法、以及構造器的物件的陣列。這樣匿名物件的類資訊就可以在執行的時候被完全確定下來,而在編譯時不需要知道任何事情。

2、如何獲取Class物件的引用

獲取Class物件的引用【返回表示該物件實際型別的Class引用】的方法,常用的有3種:
(1)Object類的getClass()方法:如果我們已經擁有我們所需要型別的物件,就可以通過呼叫getClass()方法獲取Class引用。
(2)類字面常量,資料型別的靜態屬性class
(3)Class類中的靜態方法:public static Class forName(String className).在日常的開發中,常用的是第三種方式獲取Class物件,因為是一個字串,而不是一個具體的類名。這樣我們就可以把這樣的字串配置到配置檔案中。
獲取Class物件的引用示例:

public class ReflectDemo {
    public static void main(String[] args) throws ClassNotFoundException {
        /*方式1:通過getClass()方法獲取Class物件
         * 建立同一個類不同的物件,他們的Class物件是同一個。*/
        Person person1 = new Person();
        Class clazz1 = person1.getClass();

        Person person2 = new Person();
        Class clazz2 = person2.getClass();

        System.out.println(person1 == person2);// false
        System.out.println(clazz1 == clazz2);// true

        // 方式2:通過class靜態屬性獲取Class物件
        Class clazz3 = Person.class;
        System.out.println(clazz1 == clazz3);//true

        // 方式3:Class類的靜態方法forName()
        Class clazz4 = Class.forName("cn.edu.Person");
        System.out.println(clazz1 == clazz4);//true
    }
}

3、通過Class物件獲取Constructor物件,並呼叫構造方法建立例項

(1)獲取單個構造方法

public Constructor<T> getConstructor(Class<?>... parameterTypes):
返回指定引數型別、具有public訪問許可權的建構函式
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):
返回指定引數型別、所有宣告的(包括private)建構函式

參數列示的是:你要獲取的構造方法的,構造引數個數,及資料型別的class位元組碼檔案物件

(2)獲取多個構造方法

public Constructor[] getConstructors():所有公共構造方法
public Constructor[] getDeclaredConstructors():所有構造方法

(3)通過獲得的Constructor物件,建立新例項

package cn.edu.reflect;

public class Person {
    /**
     * 3種範圍的成員變數:private, 預設,public
     * */
    private String name;
    int age;
    public String address;
    /**建構函式:無參, 有參(1,2,3個引數)*/
    public Person() {
    }
    private Person(String name) {
        this.name = name;
    }
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public Person(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }
    /**
     * 成員函式:
     * ①public, private 
     * ②有參,無參
     * ③無返回值(void),有返回值
     * */
    public void show() {
        System.out.println("show");
    }
    public void method(String s) {
        System.out.println("method " + s);
    }
    public String getString(String s, int i) {
        return s + "---" + i;
    }
    private void function() {
        System.out.println("function");
    }
    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", address=" + address+ "]";               
    }
}
public T newInstance(Object... initargs):
使用此 Constructor 物件表示的構造方法來建立該構造方法的宣告類的新例項,並用指定的初始化引數初始化該例項。

通過反射獲取構造方法並使用一:

package cn.edu.reflect;
import java.lang.reflect.Constructor;
/*通過反射獲取構造方法並使用*/
public class ReflectDemo {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("cn.edu.reflect.Person");
        //1.獲取Constructor[]
        Constructor[] constructors = clazz.getDeclaredConstructors();
         for (Constructor constructor : constructors) {
             System.out.println(constructor);
         }
        //2.獲取單個預設構造,並且使用獲得的此Constructor 物件,建立類的新例項
        Constructor con = clazz.getConstructor();//返回的是構造方法物件
        Person person1 = new Person();
        System.out.println(person1);
        //呼叫Constructor的newInstance()方法,例項化物件
        Object obj = con.newInstance();
        System.out.println(obj);
        Person person2 = (Person)obj;
        person2.show();      
    }
}
/*執行結果如下:
    public cn.edu.reflect.Person(java.lang.String,int,java.lang.String)
    cn.edu.reflect.Person(java.lang.String,int)
    private cn.edu.reflect.Person(java.lang.String)
    public cn.edu.reflect.Person()
    Person [name=null, age=0, address=null]
    Person [name=null, age=0, address=null]
    show    
 * */

通過反射去獲取該構造方法並使用二:

/* public Person(String name, int age, String address)  
   Person p = new Person("張國榮",47,"香港九龍");
   System.out.println(p);
 */ 
public class ReflectDemo2 {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("cn.edu.reflect.Person");
        /*1.獲取帶參構造方法物件*/
        Constructor con = clazz.getConstructor(String.class, int.class,String.class);           
        /*2.通過帶參構造方法物件建立物件*/
        Object obj = con.newInstance("張國榮",47,"香港九龍");      
        System.out.println(obj);
    }
}
/*Person [name=張國榮, age=47, address=香港九龍]*/  

通過反射獲取私有構造方法並使用三:

/*     
   private Person(String name){} 
   Person p = new Person("張國榮");
   System.out.println(p);
 */
public class ReflectDemo3 {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("cn.edu.reflect.Person");
        Constructor constructor = clazz.getDeclaredConstructor(String.class);
        /*用該私有構造方法建立物件,IllegalAccessException:非法的訪問異常,
              暴力訪問,值為true則指示反射的物件在使用時應該取消Java語言訪問檢查。*/
        constructor.setAccessible(true);
        Object obj = constructor.newInstance("張國榮");
        System.out.println(obj);
    }
}
/* Person [name=張國榮, age=0, address=null]*/

4、通過Class例項獲取成員變數物件,並且使用成員變數

通過發生獲取成員變數並使用

public Field[] getFields():
返回一個包含某些 Field 物件的陣列,這些物件反映此 Class 物件所表示的類或介面的所有可訪問公共欄位。
public Field getField(String name):
返回一個 Field 物件,它反映此 Class 物件所表示的類或介面的指定公共成員欄位        
public Field[] getDeclaredFields():
public Field getDeclaredField(String name):

使用程式碼例項:

public class ReflectDemo4 {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("cn.edu.reflect.Person");

        //1.獲取所有的成員變數
         Field[] fields = clazz.getDeclaredFields();
         for (Field field : fields) {
         System.out.println(field);
         }

        //2.通過無參構造方法建立物件
        Constructor constructor = clazz.getConstructor();
        Object obj = constructor.newInstance();
        System.out.println(obj);

        /*3.獲取單個的成員變數,獲取address【public】並對其賦值
         *public void set(Object obj,Object value),第一個引數是要修改欄位的物件
         * 正被修改物件的欄位的新值, 將指定物件變數上此 Field 物件表示的欄位設定為指定的新值。
         * 給obj物件的addressField欄位設定值為"香港.九龍" */
        Field addressField = clazz.getField("address");
        addressField.set(obj, "香港.九龍"); 
        System.out.println(obj);

        // 獲取name【private】並對其賦值
        Field nameField = clazz.getDeclaredField("name");
        nameField.setAccessible(true);
        nameField.set(obj, "張國榮");
        System.out.println(obj);

        // 獲取age【預設】並對其賦值
        Field ageField = clazz.getDeclaredField("age");
        ageField.setAccessible(true);
        ageField.set(obj, 47);
        System.out.println(obj);
    }
}
/*
    private java.lang.String cn.edu.reflect.Person.name
    int cn.edu.reflect.Person.age
    public java.lang.String cn.edu.reflect.Person.address
    Person [name=null, age=0, address=null]
    Person [name=null, age=0, address=香港.九龍]
    Person [name=張國榮, age=0, address=香港.九龍]
    Person [name=張國榮, age=47, address=香港.九龍]
*/

5、通過Class例項獲取Method物件,並呼叫方法

public Method[] getMethods():
返回一個包含某些 Method 物件的陣列,這些物件反映此 Class 物件所表示的類或介面
(包括那些由該類或介面宣告的以及從超類和超介面繼承的那些的類或介面)的公共 member方法。

public Method[] getDeclaredMethods():
返回 Method 物件的一個陣列,這些物件反映此 Class 物件表示的類或介面宣告的所有方法,
包括公共、保護、預設(包)訪問和私有方法,但不包括繼承的方法。

public Method getMethod(String name,Class

public class ReflectDemo5 {
    public static void main(String[] args) throws Exception {
        Class clazz = Class.forName("cn.edu.reflect.Person");
        Method[] methods = clazz.getMethods();
         for (Method method : methods) {
             System.out.println(method);
         }
        Constructor constructor = clazz.getConstructor();
        Object obj = constructor.newInstance();

        /*1 、獲取單個方法【public,無引數,無返回值】,並使用: public void show() */
        Method method1 = clazz.getMethod("show");       
        method1.invoke(obj); //呼叫obj物件的m1方法

        /*2 、獲取單個方法【public,有引數,無返回值】,並使用:public void method(String s) */
        Method method2 = clazz.getMethod("method", String.class);
        method2.invoke(obj, "hello");

        /*3 、獲取單個方法【public,有引數,有返回值】,並使用:public String getString(String s, int i)*/
        Method method3 = clazz.getMethod("getString", String.class, int.class);
        String s =(String)method3.invoke(obj, "hello", 100);
        System.out.println(s);

        //4 、獲取單個方法【private,無引數,無返回值】,private void function()
        Method method4 = clazz.getDeclaredMethod("function");
        method4.setAccessible(true);
        method4.invoke(obj);
    }
}

相關文章