Java反射機制(一)

什麼是反射?
反射機制是在【運行狀態】中:
對於任意一個類,都能夠知道這個類的所有屬性和方法;
對於任意一個對象,都能夠調用它的任意一個方法和屬性;

反射提供的功能:
在運行時判斷任意一個對象所屬的類;
在運行時構造任意一個類的對象;
在運行時判斷任意一個類所具有的成員變量和方法;
在運行時調用任意一個對象的方法。
生成動態代理

反射機制原理
Java程序在運行時,Java運行時系統一直對所有的對象進行所謂的運行時類型標識。這項信息紀錄了每個對象所屬的類。虛擬機通常使用運行時類型信息選準正確方法去執行,用來保存這些類型信息的類是Class類。也就是說,ClassLoader找到了需要調用的類時(java爲了調控內存的調用消耗,類的加載都在需要時再進行,很摳但是很有效),就會加載它,然後根據.class文件內記載的類信息來產生一個與該類相聯繫的獨一無二的Class對象。該Class對象記載了該類的字段,方法等等信息。以後jvm要產生該類的實例,就是根據內存中存在的該Class類所記載的信息(Class對象應該和我所瞭解的其他類一樣會在堆內存內產生、消亡)來進行。而java中的Class類對象是可以人工自然性的(也就是說開放的)得到的(雖然你無法像其他類一樣運用構造器來得到它的實例,因爲Class對象都是jvm產生的。不過話說回來,客戶產生的話也是無意義的),而且,更偉大的是,基於這個基礎,java實現了反射機制。

獲取Class對象三種方式:

  • 1.通過Object類的getClass()方法。例如:
    Class perClazz = new String("").getClass();
  • 2.通過Class類的靜態方法——forName()來實現:
    Class perClazz = Class.forName(“MyObject”);
  • 3.如果T是一個已定義的類型的話,在java中,它的.class文件名:T.class就代表了與其匹配的Class對象,例如:Class perClazz = Manager.class;Class c4 = int.class;
    Class perClazz = Double[].class;

獲取方法

  • //獲取所有的公共方法
    Method[] methods = perClazz.getMethods();
  • //獲取當前類的所有方法(當前類,忽略訪問修飾符限制)
    Method[] declaredMethods = perClazz.getDeclaredMethods();

獲取所有的接口

  • //Java多實現,獲取所有的接口
    Class<?>[] interfaces = perClazz.getInterfaces();

獲取父類

  • //Java單繼承,獲取父類
    Class<?> superClass = perClazz.getSuperclass();

獲取構造方法

  • //獲取所有的構造方法
    Constructor<?>[] constructors = perClazz.getConstructors();
  • //獲取指定的構造放方法,獲取類型方法時,基本類型和包裝類是不同的
    Constructor constructor = perClazz.getConstructor(int.class);

獲取類的屬性

  • //公共屬性
    Field[] fields = perClazz.getFields();
  • //所有屬性
    Field[] declaerdields = perClazz.getDeclaredFields();

修改訪問權限

  • Field.setAccessible(true);//屬性
  • Method.setAccessible(true);//方法
  • Constructor.setAccessible(true);//構造方法

調用Class屬性/方法/構造器

  • 屬性
    Field idField = perClazz.getDeclaredField(“id”);
    //修改訪問權限Field/Method.setAccessible(true);/
    idField.setAccessible(true);
    idField.set(person,1);
    System.out.println(person.getId());

  • 方法
    Method priMethod = perClazz.getDeclaredMethod(“privateMethod”,null);
    priMethod.setAccessible(true);
    priMethod.invoke(person,null);//invoke()調用方法

    Method priMethod2 = perClazz.getDeclaredMethod(“privateMethod2”,String.class);
    priMethod2.setAccessible(true);
    priMethod2.invoke(person,“JavaMan”);//invoke()調用方法

  • 構造器
    Constructor constructor = perClazz.getConstructor(int.class);
    Person person = (Person) constructor.newInstance(15);
    System.out.println(person.getId());

繞過範性類型檢查
編譯器編譯帶參數說明的集合時會去掉類型的信息,轉化爲普通的鏈表,所以運行時,將不會受到泛型的影響。所以可以這樣來繞開泛型的限制;

ArrayList<Integer> al = new ArrayList<Integer>();
		al.add(1);
		al.add(2);
		//獲取鏈表的add方法,注意這裏是Object.class,如果寫int.class會拋出NoSuchMethodException異常
		Method m = al.getClass().getMethod("add", Object.class);
		//調用反射中的add方法加入一個string類型的元素,因爲add方法的實際參數是Object
		m.invoke(al, "hello");

配置文件+反射機制
通過配置文件配置類的全路徑和部分屬性,可以創造工具類利用反射機制實現類的各種操作。

XXX.properties
ClassPath=com.javaman.reflect.Person

 //Dome.class.getClassLoader()獲取文件路徑類加載器
        InputStream in = Dome.class.getClassLoader().getResourceAsStream("XXX.properties");
        //讀取文件
        Properties properties=new Properties();
        properties.load(in);
        String ClassPath = properties.getProperty("ClassPath");

其他方法

  • 1.getName()
    一個Class對象描述了一個特定類的特定屬性,而這個方法就是返回String形式的該類的簡要描述。

  • 2.newInstance()
    該方法可以根據某個Class對象產生其對應類的實例。需要強調的是,它調用的是此類的默認構造方法。

  • 3.getClassLoader()
    返回該Class對象對應的類的類加載器。

  • 4.getComponentType()
    該方法針對數組對象的Class對象,可以得到該數組的組成元素所對應對象的Class對象。例如:
    int[] ints = new int[]{1,2,3};
    Class class1 = ints.getClass();
    Class class2 = class1.getComponentType();
    而這裏得到的class2對象所對應的就應該是int這個基本類型的Class對象。

  • 5.getSuperClass()
    返回某子類所對應的直接父類所對應的Class對象。

  • 6.isArray()
    判定此Class對象所對應的是否是一個數組對象。

代碼測試

package com.javaman.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.logging.FileHandler;

/**
 * Created by zhahongsheng on 2019/4/14.
 */
public class TestReflect {

    /**
     * 獲取反射對象(反射入口)
     */
    public static void demo1(){
        //獲取反射對象(反射入口)1。Class.forName(全類名)2.xx.Class(),3.對象.getclass()

        try {
            Class<?> perClazz = Class.forName("com.javaman.reflect.Person");
            System.out.println(perClazz);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Class<?> perClazz2= Person.class;
        System.out.println(perClazz2);

        Person per = new Person();
        Class<?> perClazz3 = per.getClass();
        System.out.println(perClazz3);
    }

    //獲取方法
    public static void demo2(){
        //Class入口
        Class<?> perClazz = null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //獲取所有的公共方法
        Method[] methods = perClazz.getMethods();
        for(Method method : methods){
            System.out.println(method);
        }

        System.out.println("=========================================================");
        //獲取當前類的所有方法(當前類,忽略訪問修飾符限制)
        Method[] declaredMethods = perClazz.getDeclaredMethods();
        for (Method method : declaredMethods){
            System.out.println(method);
        }
    }

    //獲取所有的接口
    public static void demo3(){
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Class<?>[] interfaces = perClazz.getInterfaces();
        for(Class<?> inter : interfaces ){
            System.out.println(inter);
        }
    }

    //獲取父類
    public static void demo4(){
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Class<?> superClass = perClazz.getSuperclass();
        System.out.println(superClass);
    }

    //獲取所有的構造方法
    public static void demo5() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Constructor<?>[] constructors = perClazz.getConstructors();
        for(Constructor constructor : constructors){
            System.out.println(constructor);
        }

        //獲取指定的構造放方法
        //在獲取類型方法時,基本類型和包裝類是不同的
        Constructor constructor = perClazz.getConstructor(int.class);

        Person person = (Person) constructor.newInstance(15);
        System.out.println(person.getId());

    }

    //獲取所有的公共屬性
    public static void demo6(){
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        //公共屬性
        Field[] fields = perClazz.getFields();
        for(Field field : fields){
            System.out.println(field);
        }
        //所有屬性
        Field[] declaerdields = perClazz.getDeclaredFields();
        for(Field field : declaerdields){
            System.out.println(field);
        }
    }

    public static void demo7() throws IllegalAccessException, InstantiationException, NoSuchFieldException, NoSuchMethodException, InvocationTargetException {
        Class<?> perClazz =null;
        try {
            perClazz = Class.forName("com.javaman.reflect.Person");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }

        Object instance = perClazz.newInstance();
        if(instance instanceof Person){
            Person person = (Person)instance;
            person.interfaceMethod();

            Field idField = perClazz.getDeclaredField("id");
            //修改訪問權限Field/Method.setAccessible(true);/
            idField.setAccessible(true);
            idField.set(person,1);
            System.out.println(person.getId());

            Method priMethod = perClazz.getDeclaredMethod("privateMethod",null);
            priMethod.setAccessible(true);
            priMethod.invoke(person,null);//invoke()調用方法

            Method priMethod2 = perClazz.getDeclaredMethod("privateMethod2",String.class);
            priMethod2.setAccessible(true);
            priMethod2.invoke(person,"JavaMan");//invoke()調用方法
        }
    }
    public static void main(String[] args) {
//            demo1();
//            demo2();
//            demo3();
//            demo4();
        try {
            demo5();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
//        demo6();
        try {
            demo7();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

    }


}

總結
反射機制是java框架的核心,反射機制的重點在於運行狀態下工作

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章