java反射

一.Class類的使用

1.在面向?qū)ο蟮氖澜缰杏蚁牵晔氯f(wàn)物都是對(duì)象
2.java語(yǔ)言中靜態(tài)成員和普通數(shù)據(jù)類型不是對(duì)象
3.類也是對(duì)象,是java.lang.Class的實(shí)例對(duì)象

class Foo{
    public void print()
    {
        System.out.println("it is Foo");
    }
}
public class ClassDemo1 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        
        //Foo類的實(shí)例對(duì)象
        Foo foo1 = new Foo(); //foo1表示Foo類的實(shí)例對(duì)象
        
        /*
         * Foo這個(gè)類本身也是一個(gè)實(shí)例對(duì)象禁谦,就是Class(java.lang.Class)類的實(shí)例對(duì)象
         * /任何一個(gè)類都是Class類的實(shí)例對(duì)象, 該實(shí)例對(duì)象有三種表示方法
         */
        //第一種 --> 任何一個(gè)類都有一個(gè)隱含的靜態(tài)成員變量class
        Class c1 = Foo.class; //c1表示Class類的實(shí)例對(duì)象
        
        //第二種孕豹,已知該類的對(duì)象, 通過(guò)該類對(duì)象的getClass方法表示
        Class c2 = foo1.getClass(); //c2表示Class類的實(shí)例對(duì)象
        
        /*
         * 以上c1,c2都表示Class類的實(shí)例對(duì)象,但是這個(gè)實(shí)例對(duì)象又是說(shuō)Foo這個(gè)類
         * c1,c2表示Foo類的類類型 ( class type ), 因?yàn)镕oo類可以理解為Class類的實(shí)例對(duì)象
         * 也就是世界萬(wàn)物皆對(duì)象辛辨,類也是對(duì)象捕捂,是Class類的實(shí)例對(duì)象
         * 這個(gè)對(duì)象我們稱為該類的類類型
         */
        
        //不管c1 or c2都代表了Foo類的類類型瑟枫,一個(gè)類只可能是Class類的一個(gè)實(shí)例對(duì)象, 所以c1=c2
        System.out.println(c1==c2);//輸出: true
        
        //第三種
        Class c3 = null;
        try {
            c3 = Class.forName("com.lxf.reflect.Foo");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(c3==c2); //輸出:true
        
        //我們可以通過(guò)類的類類型創(chuàng)建該類的實(shí)例--->通過(guò)c1 or c2 or c3創(chuàng)建Foo的實(shí)例
        try {
            Foo foo2 = (Foo)c2.newInstance(); //需要有無(wú)參數(shù)的構(gòu)造方法
            foo2.print();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

二.靜態(tài)加載

  • 在編譯java源文件的時(shí)候的加載類叫做靜態(tài)加載,比如:Test.java文件如下
class Test{
  public static void main(String[] args) {
      People p = new People();
      p.eat();
  }
}

編譯Test.java

javac Test.java
這時(shí)候People.class字節(jié)碼文件并沒(méi)有,所以在編譯的時(shí)候會(huì)報(bào)錯(cuò)

創(chuàng)建People.java

class People
{
  public void eat()
  {
        System.out.println("我喜歡美食");
  }
}

此時(shí)在編譯

先編譯People.java
javac People.java //編譯后會(huì)產(chǎn)生People.class字節(jié)碼文件
javac Test.java     //編譯后會(huì)產(chǎn)生Test.class字節(jié)碼文件

執(zhí)行Test

java Test  //會(huì)輸出:我喜歡美食

三.動(dòng)態(tài)加載

Java的一個(gè)強(qiáng)大的特性是能夠動(dòng)態(tài)加載一個(gè)給定名稱的類指攒,而事先不需要指導(dǎo)這個(gè)類的名字慷妙。這個(gè)特性使得Java的開(kāi)發(fā)人員能夠構(gòu)造一個(gè)不需要重新編譯即可擴(kuò)展和修改的靈活動(dòng)態(tài)的系統(tǒng),在Java中允悦,動(dòng)態(tài)加載通常是調(diào)用類 java.lang.ClassforName 方法來(lái)實(shí)現(xiàn)膝擂;
 
問(wèn)題描述:
例如,下面的代碼在Main方法中調(diào)用ClassLoader來(lái)加載一個(gè)命令行傳入的class.
LoaderTest.java文件

package aa
public class LoaderTest
{
    public static void main(String[] args)
    {
        LoadClass(args[0]);
    }

    public static void LoadClass(String clsName)
    {
        try
        {
             beLoaded bl = 
            (beLoaded)Class.forName(clsName).newInstance();
            bl.PrintInfo();
         }
         catch (Exception e)
        {
            e.printStackTrace();
        }

      }
}

beLoaded.java文件

package aa;
public class beLoaded
{
    public void PrintInfo()
    {
        System.out.println("I am be loaded!");
    }
}

上面的代碼在正常情況下非常好使隙弛,并且使得整個(gè)系統(tǒng)可以同具體的java類分離開(kāi)來(lái)架馋,只需要傳入一個(gè)class的類名即可完成功能調(diào)用。而且從擴(kuò)展的角度來(lái)說(shuō)全闷,定義一些從beLoaded類上繼承下來(lái)的類叉寂,并將類名通過(guò)參數(shù)傳入系統(tǒng),即可實(shí)現(xiàn)各種不同的功能類的調(diào)用室埋,非常方便办绝。
在命令行上鍵入如下命令:

java aa.LoaderTest aa.beLoaded
屏幕會(huì)輸出下面的內(nèi)容:
I am be loaded!

下面我們創(chuàng)建一個(gè)beLoaded的子類,類名叫做beLoadedChild姚淆,代碼如下:

package aa;
public class beLoadedChild extends beLoaded
{
    public void PrintInfo()
    {
        System.out.println("I am be loaded and I am Child");
    }
}

在命令行上鍵入如下命令:

java aa.LoaderTest aa.beLoadedChild
屏幕會(huì)輸出下面的內(nèi)容:
I am be loaded and I am Child

通過(guò)上面的例子我們可以看出孕蝉,只要設(shè)計(jì)好LoaderTest這個(gè)類和beLoaded類,就可以實(shí)現(xiàn)系統(tǒng)的擴(kuò)展性腌逢,對(duì)不同的功能目標(biāo)調(diào)用不同的beLoaded的子類降淮,LoaderTest類beLoaded類是不需要重新編譯的,系統(tǒng)十分的靈活和方便搏讶。

四.基本數(shù)據(jù)類型佳鳖,void關(guān)鍵字都存在類類型

        //int的類類型
        Class c1 = int.class;
        System.out.println(c1.getName());
        
        //String的類類型, String的字節(jié)碼
        Class c2 = String.class;
        System.out.println(c2.getName());
        
        Class c3 = double.class;
        Class c4 = Double.class;
        Class c5 = void.class;
        Class c6 = Package.class;

五.Class類的基本API

  • 獲取類的所有方法
    /**
     * 打印類的信息,成員方法
     * @param obj 
     */
    public static  void printMethodMessage(Object obj)
    {
        //獲取參數(shù)對(duì)象類的類類型, 參數(shù)傳遞的是哪個(gè)子類的對(duì)象媒惕,c就代表該子類的類類型
        Class c = obj.getClass();
        System.out.println("類名為:" + c.getName());
        
        /*
         * 獲取類的成員方法:
         * 成員方法是java.lang.reflect.Method的對(duì)象
         * 一個(gè)成員方法就是一個(gè)Method對(duì)象
         * getMethods() 方法獲取的是所有Public類型的函數(shù)系吩,包括從父類繼承來(lái)的
         * getDeclaredMethods() 獲取的是所有該類自己聲明的方法,不問(wèn)訪問(wèn)權(quán)限
         */
        //獲取參數(shù)對(duì)象類的所有方法
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            //獲取方法的返回值類類型
            Class returnType = method.getReturnType();
            //打印方法返回值類型
            System.out.print(returnType.getName());
            System.out.print("方法名為:" + method.getName() + " ( ");
            //獲取返回值類型---->得到的是參數(shù)列表的類類型( int.class, String.class等 )
            Class[] paramTypes = method.getParameterTypes();
            for (Class c1 : paramTypes) {
                System.out.print(c1.getName() + ",");
            }
            System.out.println(" ) ");          
        }
    }
  • 獲取類所有的屬性
    /*
     * 獲取類的成員屬性
     * 
     * 成員屬性是java.lang.reflect.Field的對(duì)象
     * Field類封裝了關(guān)于成員屬性的操作
     * getFields() 方法獲取的是所有public的成員變量的信息
     * getDeclaredField() 獲取的是該類自己聲明的成員屬性的信息(包括私有)
     */
    private static void printFieldMessage(Object obj) {
        Class c = obj.getClass();
        Field[] fs = c.getDeclaredFields();
        for (Field field : fs) {
            //得到類成員屬性類型的類類型(  int.class, String.class等等)
            Class fieldType = field.getType();
            //獲取成員屬性類型名
            String typeName  = fieldType.getName();
            //獲取成員屬性名
            String fieldName = field.getName();
            System.out.println(typeName + " " + fieldName);
        }
    }
  • 獲取類所有構(gòu)造方法的信息
    /*
     * 打印對(duì)象構(gòu)造方法的信息
     */
    public static void printConMessage(Object obj)
    {
        Class c = obj.getClass();
        /*
         * 構(gòu)造函數(shù)也是對(duì)象
         * java.lang.Constructor中封裝了構(gòu)造函數(shù)的信息
         * getConstructors 獲取所有Pubic的構(gòu)造函數(shù)
         * getDeclaredConstructors 獲取所有構(gòu)造方法
         */
        //Constructor[] cs = c.getConstructors();
        Constructor[] cs = c.getDeclaredConstructors();
        for (Constructor constructor : cs) {
            System.out.println(constructor.getName());
            //獲取構(gòu)造函數(shù)的參數(shù)列表《饰怠--- 得到的是參數(shù)列表的類類型
            Class[] paramTypes = constructor.getParameterTypes();
            for (Class class1 : paramTypes) {
                System.out.print(class1.getName() + ", ");
            }
            System.out.println(" ) ");
        }
    }
  • 獲取類方法穿挨,屬性,構(gòu)造方法的測(cè)試
    public static void main(String[] args) {
        String test = "hello";
        System.out.println("得到類的成員方法信息:");
        ClassUtil.printMethodMessage(test);
        
        System.out.println("得到類的成員屬性信息:");
        ClassUtil.printFieldMessage(test);
        
        System.out.println("得到類的構(gòu)造方法信息:");
        ClassUtil.printConMessage("hello world");
    }

五.方法的反射

class A{
    public void print(int a, int b)
    {
        System.out.println(a+b);
    }
}

//獲取print(int, int)方法, 要獲取方法肴盏,就是獲取類的信息科盛,首先獲取類的類型s
    public static void main(String[] args){
        A a1 = new A();
        Class c= a1.getClass();
        /**
         * 獲取方法名和參數(shù)列表
         * getMethod() 獲取public方法
         * getDelcaredMethod 獲取自己聲明的方法
         */
            Method m = c.getMethod("print", new Class[]{int.class,int.class});
            //Method m2 =  c.getMethod("print", int.class, int.class); 和上面一行等效
            
            //方法的反射,用m對(duì)象進(jìn)行方法的調(diào)用,和a1.print(10,20)效果相同
            //方法如果沒(méi)有返回值則返回null, 否則返回具體的返回值
            Object o = m.invoke(a1, new Object[]{10,20}); //或m.invoke(a1, 10,20); //輸出30
}

五.通過(guò)Class,Method了解泛型的本質(zhì)

  • 我們先看一段代碼
        ArrayList list1 = new ArrayList();
        ArrayList<String>  list2 = new ArrayList<String>();
        Class c1 = list1.getClass();
        Class c2 = list2.getClass();
        System.out.println(c1==c2);//輸出結(jié)果為true
        //list2.add(100); //會(huì)報(bào)錯(cuò)菜皂,因?yàn)閘ist2定義的是String類型

可以看到以上list1是未定義泛型的贞绵,而list2定義為String類型的泛型,
以上 c1==c2 打印輸出 true, 說(shuō)明編譯后集合的泛型是 去泛型化的恍飘,也就證明了java中集合的泛型榨崩,是防止錯(cuò)誤輸入的谴垫,只在編譯階段有效,繞過(guò)編譯就無(wú)效了.

  • 我們現(xiàn)在通過(guò)方法的反射蜡饵,調(diào)用list2.add()方法添加非String類的數(shù)據(jù)
        try {
            Method m = c1.getMethod("add", Object.class);
            m.invoke(list2, 10); //繞過(guò)編譯操作弹渔,等同于繞過(guò)了泛型
            System.out.println(list2.size());//輸出1
        } catch (Exception e) {
            // TODO: handle exception
        }

以上代碼可以正常運(yùn)行胳施,我們想list2中添加了100整型溯祸,卻添加成功了,說(shuō)明我們的 反射機(jī)制繞過(guò)編譯階段 的舞肆,直接體現(xiàn)在 運(yùn)行階段焦辅;

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市椿胯,隨后出現(xiàn)的幾起案子筷登,更是在濱河造成了極大的恐慌,老刑警劉巖哩盲,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件前方,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡廉油,警方通過(guò)查閱死者的電腦和手機(jī)惠险,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)抒线,“玉大人班巩,你說(shuō)我怎么就攤上這事∷惶浚” “怎么了抱慌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)眨猎。 經(jīng)常有香客問(wèn)我抑进,道長(zhǎng),這世上最難降的妖魔是什么睡陪? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任寺渗,我火速辦了婚禮,結(jié)果婚禮上宝穗,老公的妹妹穿的比我還像新娘户秤。我一直安慰自己,他們只是感情好逮矛,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開(kāi)白布鸡号。 她就那樣靜靜地躺著,像睡著了一般须鼎。 火紅的嫁衣襯著肌膚如雪鲸伴。 梳的紋絲不亂的頭發(fā)上府蔗,一...
    開(kāi)封第一講書(shū)人閱讀 51,258評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音汞窗,去河邊找鬼姓赤。 笑死,一個(gè)胖子當(dāng)著我的面吹牛仲吏,可吹牛的內(nèi)容都是我干的不铆。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼裹唆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼誓斥!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起许帐,我...
    開(kāi)封第一講書(shū)人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤劳坑,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后成畦,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體距芬,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年循帐,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了框仔。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡惧浴,死狀恐怖存和,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情衷旅,我是刑警寧澤捐腿,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布,位于F島的核電站柿顶,受9級(jí)特大地震影響茄袖,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜嘁锯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一宪祥、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧家乘,春花似錦蝗羊、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至业崖,卻和暖如春野芒,著一層夾襖步出監(jiān)牢的瞬間蓄愁,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工狞悲, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留撮抓,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓摇锋,卻偏偏與公主長(zhǎng)得像丹拯,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子乱投,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法咽笼,類相關(guān)的語(yǔ)法顷编,內(nèi)部類的語(yǔ)法戚炫,繼承相關(guān)的語(yǔ)法,異常的語(yǔ)法媳纬,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,625評(píng)論 18 399
  • 一双肤、概述 Java反射機(jī)制定義 Java反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類钮惠,都能夠知道這個(gè)類中的所有屬性和方法...
    CoderZS閱讀 1,634評(píng)論 0 26
  • 1. 了解 Java 中的反射 1.1 什么是 Java 的反射 Java 反射是可以讓我們?cè)谶\(yùn)行時(shí)獲取類的函數(shù)茅糜、...
    Ten_Minutes閱讀 537評(píng)論 0 4
  • 最近《微微一笑很傾城》的火爆幾度刷新了國(guó)產(chǎn)偶像劇新的里程碑,一向不看好國(guó)產(chǎn)偶像劇的我也鬼使神差地加入了此劇的粉絲行...
    談?wù)刴inda閱讀 593評(píng)論 3 7
  • 一只貓童心大發(fā)素挽,在追逐自己的尾巴 將身體躬成一個(gè)環(huán)蔑赘,奔跑 我也想抓住 那條呼嘯而過(guò)的尾巴 關(guān)于一條...
    禾鄉(xiāng)閱讀 323評(píng)論 2 14