Java的反射機制

概念:在某些特殊場合中編寫代碼時不確定要創(chuàng)建什么類型的對象掂之,也不確定要調(diào)用什么樣的方法掠哥,這些都希望通過運行時傳遞的參數(shù)來決定霞赫,該機制叫做動態(tài)編程技術(shù)梁棠,也就是反射機制

通俗來說置森,反射機制就是用于動態(tài)創(chuàng)建對象并且動態(tài)調(diào)用方法的機制

Class類:

  • Class類的實例可以用于描述Java應(yīng)用程序中的類和接口,也就是一種數(shù)據(jù)類型
  • 該類沒有公共構(gòu)造方法掰茶,該類的實例由Java虛擬機和類加載器自動構(gòu)造完成暇藏,本質(zhì)上就是加載到內(nèi)存中的運行時類

獲取Class對象的方式:

  • 使用數(shù)據(jù)類型.Class的方式可以獲取對應(yīng)類型的Class對象(較常用)
        //1. 使用數(shù)據(jù)類型.class的方式可以獲取對應(yīng)類型的Class對象
        Class c1 = String.class;
        System.out.println("c1 = " + c1);   //自動調(diào)用toString方法,返回類的完全限定名: class java.lang.String

        c1 = int.class;
        System.out.println("c1 = " + c1);   //返回基本數(shù)據(jù)類型的名稱 int

        c1 = void.class;
        System.out.println("c1 = " + c1);   //返回void void
輸出
  • 使用引用/對象.getClass()的方式可以獲取對應(yīng)類型的Class對象
        //2. 使用對象.getClass()的方式獲取對應(yīng)的Class對象
        String str1 = new String("hello");
        c1 = str1.getClass();
        System.out.println("c1 = " + c1);   //class java.lang.String

        Integer it1 = 20;
        c1 = it1.getClass();
        System.out.println("c1 = " + c1);   //class java.lang.Integer

        int num = 5;
        //num.getClass();   //基本數(shù)據(jù)類型的變量不能調(diào)用方法
輸出
  • 使用包裝類.TYPE的方式可以獲取對應(yīng)基本數(shù)據(jù)類型的Class對象
        //3. 使用包裝類.TYPE的方式來獲取對應(yīng)基本數(shù)據(jù)類型的Class對象
        c1 = Integer.TYPE;
        System.out.println("c1 = " + c1);   //int
輸出
  • 使用Class.forName()的方式來獲取參數(shù)指定類型的Class對象(完整名稱:包名.類名濒蒋,不能獲取基本數(shù)據(jù)類型的Class對象)(較常用)
        //4. 調(diào)用Class類中的forName方法來獲取對應(yīng)的Class對象
        //c1 = Class.forName("String"); //Error 必須寫完整的包名
        //c1 = Class.forName("int");    //不能獲取基本數(shù)據(jù)類型的Class對象
        c1 = Class.forName("java.lang.String");
        System.out.println("c1 = " + c1);   //class java.lang.String
輸出
  • 使用類加載器ClassLoader的方式獲取指定類型的Class對象
        //5. 使用類加載器的方式來獲取Class對象
        ClassLoader classLoader = ClassTest.class.getClassLoader();
        c1 = classLoader.loadClass("java.lang.String");
        System.out.println("c1 = " + c1);
輸出

常用方法:

  • static Class<?> forName(String className):用于獲取參數(shù)指定類型對應(yīng)的Class對象并返回
  • T newInstance():用于創(chuàng)建該Class對象所表示類的新實例(已過時)
/**
 * 用于測試的簡單Person類
 */
public class Person {

    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public Person() {
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
        //1. 使用原始方式以無參形式構(gòu)造Person類的對象并打印
        Person p1 = new Person();
        System.out.println("無參方式創(chuàng)建的對象是:" + p1);

        System.out.println("----------------------------------------------");

        //2. 使用反射機制以無參行駛構(gòu)造Person類型的對象并打印
        Class c1 = Class.forName("Person");
        System.out.println("無參方式創(chuàng)建的對象是:" + c1.newInstance());
輸出

Constructor類:主要用于描述獲取到的構(gòu)造方法信息

class類常用方法:

  • Constructor<T> getConstructor(Class<?>... parameterTypes):用于獲取此Class對象所表示類型中參數(shù)指定的公共構(gòu)造方法
        //1. 使用原始方式以無參形式構(gòu)造Person類的對象并打印
        Person p1 = new Person();
        System.out.println("無參方式創(chuàng)建的對象是:" + p1);

        System.out.println("----------------------------------------------");

        //2. 使用反射機制以無參行駛構(gòu)造Person類型的對象并打印
        Class c1 = Class.forName("Person");
        //System.out.println("無參方式創(chuàng)建的對象是:" + c1.newInstance());
        //獲取Class對象對應(yīng)類中的無參構(gòu)造方法盐碱,也就是Person類中的無參構(gòu)造方法
        Constructor constructor = c1.getConstructor();
        //使用獲取到的無參構(gòu)造方法來構(gòu)造對應(yīng)類型的對象,也就是Person類型的對象
        System.out.println("無參方式創(chuàng)建的對象是:" + constructor.newInstance());

        System.out.println("----------------------------------------------");
        //3. 使用原始方式以有參方式構(gòu)造Person類的對象并打印
        Person p2 = new Person("張三", 20);
        System.out.println("有參構(gòu)造方式創(chuàng)建的對象是:" + p2);

        System.out.println("----------------------------------------------");
        //4. 使用反射機制以有參方式構(gòu)造Person類型的對象并打印
        //獲取Class對象對應(yīng)類中的有參構(gòu)造方法沪伙,也就是Person類中的有參構(gòu)造方法
        Constructor constructor1 = c1.getConstructor(String.class, int.class);
        //使用獲取到的有參構(gòu)造方法來構(gòu)造對應(yīng)類型的對象瓮顽,也就是Person類型的對象
        //newInstance方法中的實參是用于給有參構(gòu)造方法的形參進行初始化的,也就是給name和age進行初始化的
        System.out.println("有參構(gòu)造方式創(chuàng)建的對象是:" + constructor1.newInstance("張三", 20));
輸出
  • Constructor<?>[] getConstructors():用于獲取此Class對象所表示類型中所有的公共構(gòu)造方法
        //5. 使用反射機制獲取Person類中所有的公共構(gòu)造方法并打印
        Constructor[] constructors = c1.getConstructors();
        for (Constructor ct : constructors) {
            System.out.println("構(gòu)造方法的訪問修飾符是:" + ct.getModifiers());
            System.out.println("構(gòu)造方法的方法名稱是:" + ct.getName());
            Class[] parameterTypes = ct.getParameterTypes();
            System.out.println("構(gòu)造方法的所有參數(shù)類型是:");
            for (Class cs : parameterTypes) {
                System.out.print(cs + " ");
            }
            System.out.println();
            System.out.println("----------------------------------------------");
輸出

相關(guān)的訪問修飾符

Construcotr類常用方法:

  • T newInstance(Object... initargs):使用此Constructor對象描述的構(gòu)造方法來構(gòu)造Class對象代表類型的新實例
  • int getModifiers():獲取方法的訪問修飾符
  • String getName():獲取方法的名稱
  • Class<?>[] getParameterTypes():獲取方法的所有參數(shù)的類型

Field類:主要用于描述獲取到的單個成員變量信息

class類常用方法:

  • Field getDeclaredField(String name):用于獲取此Class對象所表示類中參數(shù)指定的單個成員變量信息
  • Field[] getDeclaredFields():用于獲取此Class對象所表示類中所有成員變量信息
        //1. 使用原始方式來構(gòu)造對象以及獲取成員變量的數(shù)值并打印
        Person p1 = new Person("張三", 20);
        System.out.println("獲取到的成員變量數(shù)值為:" + p1.getName());  //張三

        System.out.println("------------------------------------------------");
        //2. 使用反射機制來構(gòu)造對象以及獲取成員變量的數(shù)值并打印
        //2.1 獲取Class對象
        Class c1 = Class.forName("Person");
        //2.2 根據(jù)Class對象獲取對應(yīng)的有參構(gòu)造方法
        Constructor constructor = c1.getConstructor(String.class, int.class);
        //2.3 使用有參構(gòu)造方法來得到Person類型的對象
        Object object = constructor.newInstance("張三", 20);
        //2.4 根據(jù)Class對象獲取對應(yīng)的成員變量信息
        Field field = c1.getDeclaredField("name");
        //2.5 使用Person類型的對象來獲取成員變量的信息
        //獲取對象object中名字為field成員變量的數(shù)值围橡,也就是成員變量name的數(shù)值
        System.out.println("獲取到的成員變量數(shù)值為:" + field.get(object));
輸出

Field類常用方法:

  • Object get(Object obj):獲取參數(shù)對象obj中此Field對象所表示成員變量的數(shù)值

  • void set(Object obj, Object value):將參數(shù)對象obj中此Field對象表示成員變量的數(shù)值修改為參數(shù)value的數(shù)值

  • void setAccessible(boolean flag):當實參傳遞true時暖混, 則反射對象在使用時應(yīng)該取消Java語言訪問檢查

  • int getModifiers():獲取成員變量的訪問修飾符

  • Class<?> getType():獲取成員變量的數(shù)據(jù)類型

  • String getName():獲取成員變量的名稱

        //3. 使用原始方式修改指定對象中成員變量的數(shù)值后再次打印
        p1.setName("李四");
        System.out.println("修改后成員變量的數(shù)值為:" + p1.getName());

        System.out.println("------------------------------------------------");
        //4. 使用反射機制修改指定對象中成員變量的數(shù)值后再次打印
        //表示修改對象object中名字為field成員變量的數(shù)值為李四,也就是成員變量name的數(shù)值為李四
        field.set(object, "李四");
        System.out.println("修改后成員變量的數(shù)值為:" + field.get(object));

        System.out.println("------------------------------------------------");
        //5. 獲取Class類對象對應(yīng)類中所有的成員變量
        Field[] declaredFields = c1.getDeclaredFields();
        for (Field ft : declaredFields) {
            System.out.println("獲取到的訪問修飾符為:" + ft.getModifiers());
            System.out.println("獲取到的數(shù)據(jù)類型為:" + ft.getType());
            System.out.println("獲取到的成員變量名稱是:" + ft.getName());
            System.out.println("------------------------------------------------");
輸出

Method類:主要用于描述獲取到的單個成員方法信息

Class類常用方法:

  • Method getMethod(String name, Class<?>... parameterTypes):用于獲取該Class對象表示類中名字為name翁授,參數(shù)為parameterTypes的指定公共成員方法
  • Method[] getMethods():用于獲取該Class對象表示類中所有公共成員方法

Method類常用方法:

  • Object invoke(Object obj, Object... args):使用對象obj來調(diào)用此Method對象所表示的成員方法拣播,實參傳遞args
  • int getModifiers():獲取方法的訪問修飾符
  • Class<?> getReturnType():獲取方法的返回值類型
  • String getName():獲取方法的名稱
  • Class<?>[] getParameterTypes():獲取方法所有參數(shù)的類型
  • Class<?>[] getExceptionTypess():獲取方法的異常信息
        //1. 使用原始方式構(gòu)造對象并調(diào)用方法打印結(jié)果
        Person p1 = new Person("張三", 20);
        System.out.println("調(diào)用方法的返回值是:" + p1.getName());

        System.out.println("--------------------------------------------");
        //2. 使用反射機制構(gòu)造對象并調(diào)用方法打印結(jié)果
        //2.1 獲取Class對象
        Class c1 = Class.forName("Person");
        //2.2 根據(jù)Class對象來獲取對應(yīng)的有參構(gòu)造方法
        Constructor constructor = c1.getConstructor(String.class, int.class);
        //2.3 使用有參構(gòu)造方法構(gòu)造對象并記錄
        Object object = constructor.newInstance("張三", 20);
        //2.4 根據(jù)Class對象來獲取對應(yīng)的成員方法
        Method method = c1.getMethod("getName");
        //2.5 使用對象調(diào)用成員方法進行打印
        //表示使用object對象調(diào)用method表示的方法晾咪,也就是調(diào)用getName來獲取姓名
        System.out.println("調(diào)用方法的返回值是:" + method.invoke(object));

        System.out.println("--------------------------------------------");
        //3. 使用反射機制來獲取類中的所有成員方法并打印
        Method[] methods = c1.getMethods();
        for (Method mt : methods) {
            System.out.println("成員方法的修飾符是:" + mt.getModifiers());
            System.out.println("成員方法的返回值類型是:" + mt.getReturnType());
            System.out.println("成員方法的名稱是:" + mt.getName());
            System.out.println("成員方法的形參列表是:");
            Class<?>[] parameterTypes = mt.getParameterTypes();
            for (Class<?> ct : parameterTypes) {
                System.out.println(ct + "");
            }
            System.out.println("成員方法的異常類型列表是:");
            Class<?>[] exceptionTypes = mt.getExceptionTypes();
            for (Class<?> ct : exceptionTypes) {
                System.out.println(ct + " ");
            }
            System.out.println();
            System.out.println("--------------------------------------------");
        }
輸出1

輸出2

輸出3

獲取其他結(jié)構(gòu)信息的方法:

  • Package getPackage():獲取所在的包的信息
  • Class<? super T> getSuperclass():獲取繼承的父類的信息
  • Class<?>[] getInterfaces():獲取實現(xiàn)的所有接口
  • Annotation[] getAnnotations():獲取注解信息
  • Type[] getGenericInterfaces():獲取泛型信息
/**
 * Student類
 * @param <T>
 * @param <E>
 */
@MyAnnotation
public class Student<T, E> extends Person implements Comparable<String>, Serializable {

    @Override
    public int compareTo(String o) {
        return 0;
    }
}
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * 自定義注解
 */
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
        //獲取Student類型的Class對象
        Class c1 = Class.forName("Student");
        System.out.println("獲取到的包信息是:" + c1.getPackage());
        System.out.println("獲取到的父類信息是:" + c1.getSuperclass());
        System.out.println("獲取到的接口信息是:");
        Class[] interfaces = c1.getInterfaces();
        for (Class ct : interfaces) {
            System.out.println(ct + "");
        }
        System.out.println();
        System.out.println("-----------------------------------------------");

        System.out.println("獲取到的注解信息是:");
        Annotation[] annotations = c1.getAnnotations();
        for (Annotation at : annotations) {
            System.out.println(at + " ");
        }
        System.out.println();
        System.out.println("-----------------------------------------------");

        System.out.println("獲取到的泛型信息是:");
        Type[] genericInterfaces = c1.getGenericInterfaces();
        for (Type tt : genericInterfaces) {
            System.out.println(tt + " ");
        }
        System.out.println();
輸出
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市贮配,隨后出現(xiàn)的幾起案子谍倦,更是在濱河造成了極大的恐慌,老刑警劉巖泪勒,帶你破解...
    沈念sama閱讀 206,723評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件昼蛀,死亡現(xiàn)場離奇詭異,居然都是意外死亡圆存,警方通過查閱死者的電腦和手機叼旋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,485評論 2 382
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來沦辙,“玉大人夫植,你說我怎么就攤上這事∨陆危” “怎么了偷崩?”我有些...
    開封第一講書人閱讀 152,998評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長撞羽。 經(jīng)常有香客問我阐斜,道長,這世上最難降的妖魔是什么诀紊? 我笑而不...
    開封第一講書人閱讀 55,323評論 1 279
  • 正文 為了忘掉前任谒出,我火速辦了婚禮,結(jié)果婚禮上邻奠,老公的妹妹穿的比我還像新娘笤喳。我一直安慰自己,他們只是感情好碌宴,可當我...
    茶點故事閱讀 64,355評論 5 374
  • 文/花漫 我一把揭開白布杀狡。 她就那樣靜靜地躺著,像睡著了一般贰镣。 火紅的嫁衣襯著肌膚如雪呜象。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,079評論 1 285
  • 那天碑隆,我揣著相機與錄音恭陡,去河邊找鬼。 笑死上煤,一個胖子當著我的面吹牛休玩,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 38,389評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼拴疤,長吁一口氣:“原來是場噩夢啊……” “哼永部!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起呐矾,我...
    開封第一講書人閱讀 37,019評論 0 259
  • 序言:老撾萬榮一對情侶失蹤扬舒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后凫佛,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,519評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡孕惜,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,971評論 2 325
  • 正文 我和宋清朗相戀三年愧薛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片衫画。...
    茶點故事閱讀 38,100評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡毫炉,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出削罩,到底是詐尸還是另有隱情瞄勾,我是刑警寧澤,帶...
    沈念sama閱讀 33,738評論 4 324
  • 正文 年R本政府宣布弥激,位于F島的核電站进陡,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏微服。R本人自食惡果不足惜趾疚,卻給世界環(huán)境...
    茶點故事閱讀 39,293評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望以蕴。 院中可真熱鬧糙麦,春花似錦、人聲如沸丛肮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,289評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽宝与。三九已至焚廊,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伴鳖,已是汗流浹背节值。 一陣腳步聲響...
    開封第一講書人閱讀 31,517評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留榜聂,地道東北人搞疗。 一個月前我還...
    沈念sama閱讀 45,547評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親匿乃。 傳聞我的和親對象是個殘疾皇子桩皿,可洞房花燭夜當晚...
    茶點故事閱讀 42,834評論 2 345