歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Java框架基礎——反射(reflect)

閱讀目錄

  • 一、Class類的使用
  • 二、動態加載類
  • 三、獲取方法信息
  • 四、獲取成員變量、構造函數信息
  • 五、方法的反射
  • 六、通過反射了解集合泛型的本質

一、Class類的使用

1)在面向對象(oop)的世界裡,萬事萬物皆對象。
  在Java中,包括基本的數據類型,都是對象。
  Class c = int.class;//int 的類類型
  那就是說:
  類是對象,類是java.lang.Class類的實例對象。這個對象我們稱之為類類型。
  換言之,每一個類都有一個類類型,這個類類型就是java.lang.Class的實例對象
2)如何獲取一個類的類類型(三種方法)

  • 類名.class;
  • 類的對象.getClass();
  • Class.forName(“類的全稱包含包名”);

  class Foo{}
  Foo foo1=new Foo();
  1. Class c1 = Foo.Class;//任何一個類都有一個隱含的靜態成員變量class
  2. Class c2 = foo1.getClass()//已經知道該類的對象通過getClassF方法
  3. Class c3 = null;
  c3 = Class.forName("com.immoc.reflect.Foo");
  //of course, c1 == c2 == c3 is true
3)利用類類型來創造實例對象(需要有無參數的構造方法)(需要有強制類型轉化,且有異常拋出)
  Foo foo2 = (Foo)(c1.newInstance());
  Foo foo3 = (Foo)(c2.newInstance());
  Foo foo4 = (Foo)(c3.newInstance());

 
 1 package com.study.reflect;
 2 
 3 /**
 4  * @description 
 5  * @author zhangqianqian
 6  * @date 2016-3-28 下午4:06:29 
 7  */
 8 public class ClassDemo1 {
 9 
10     public static void main(String[] args){
11         //Foo的實例對象如何表示?
12         Foo foo1=new Foo();//foo1就表示Foo的實例對象
13         //Foo這個類也是一個實例對象,它是Class類的對象,那Class類的實例對象,如何表示呢?
14         //任何一個類都是Class的實例對象,但是不能通過new關鍵字來創建。這個實例對象有三種表示方式:
15         
16         //第一種表示方式---->實際是在告訴我們任何一個類都有一個隱含的靜態成員變量class
17         Class c1=Foo.class;//如果Foo已經存在,可以用這種方法來創建Foo的類類型(class type),即Foo類的類類型就是Class類的一個實例對象。
18         
19         //第二種方式-->已知該類的對象,通過getClass方法
20         Class c2=foo1.getClass();//如果Foo類的對象foo1已經存在,可以通過這種方法來創建Foo類的類類型。
21         
22         /**
23          * 上面官網說c1,c2 是表示了Foo類的類類型(class type)---->指的就是Class的對象
24          * 類類型,即萬事萬物皆對象,
25          * 類也是一個對象,是Class類的實例對象
26          * 這個對象我們把它稱為該類的類類型
27          */
28         
29         //不管c1 or c2,他們都代表了Foo類的類類型,一個類只可能是Class類的一個實例對象
30         System.out.println(c1==c2);//true
31         
32         //第三種表示:
33         Class c3=null;
34         try {
35             c3=Class.forName("com.study.reflect.Foo");//通過Foo的全稱來創建
36         } catch (ClassNotFoundException e) {
37             e.printStackTrace();
38         }
39         System.out.println(c2==c3);//true
40         
41         //我們完全可以通過類的類類型創建該類的對象實例-->通過c1 or c2 or c3 創建Foo的實例
42         try {
43             //如果c1是A類的類類型,創建的就是A類的實例對象,所以需要做強制類型轉換,也會有異常
44             Foo foo = (Foo) c1.newInstance();//這個前提要求是需要有無參數的構造方法
45             foo.print();
46         } catch (InstantiationException e) {
47             e.printStackTrace();
48         } catch (IllegalAccessException e) {
49             e.printStackTrace();
50         }
51     }
52     
53 }
54 class Foo{
55     void print(){
56     }
57 }

二、動態加載類

首先區分什麼是動態加載和靜態加載。

也就是區分編譯和運行。

  • new 創建對象,是靜態加載類,在編譯時刻就需要加載所有可能使用到的類
  • 通過動態加載類可以解決該問題。通過類類型創建該類的對象

1、靜態加載類,是編譯時刻加載;動態加載類,是運行時刻加載
2、new創建對象:是靜態加載類,在編譯時刻就需要加載所有的【可能使用到的類】。有一個類有問題(如不存在),都不能通過編譯,會報錯。
3、Class.forName()通過動態加載類,可以用到一個類時,才進行加載。
【功能性的類盡量使用動態加載,並對新添的類實現功能性接口(標准),這樣就不用重新編譯】

比如:

//new 創建對象是靜態加載類,在編譯時刻就需要加載所有的可能使用到的類。eg:word excel
//通過動態加載類可以解決該問題
//動態加載類,在運行時刻加載
Class c=Class.forName(args[0]);
//通過類類型,創建該類對象
OfficeAble oa=(OfficeAble)c.newInstance();//word 和excel都想加載就用一個標准oa
oa.start();
—————————————————————————————————
//編寫一個標准接口
interface OfficeAble
{
public void start();
}
—————————————————————————————————
//讓word 和excel繼承oa
class Excel implements OfficeAble
{
    public void start(){
}
}

動態加載的好處(設計思想):
擴展性,主程序不需要修改,不需要重新編譯,只要新功能實現了相同的接口,啟動的時候換個新的參數就可以。

三、獲取方法信息

public class ClassDemo2 {
    public static void main(String[] args) {
        /**
         * 基本數據類型、void關鍵字都存在類類型
         */
        Class c1=int.class;//基本數據類型int的類類型
        Class c2=String.class;//String類的類類型(可以理解為String類的字節碼,如:編譯生成的xx.class文件即xx的字節碼文件)
        Class c3=double.class;//double這個數據類型的類類型
        Class c4=Double.class;//Double這個類的類類型
        Class c5=void.class;//在類裡面聲明的,比如void,也是有類類型
        
        //獲取類的全稱getName()
        System.out.println(c1.getName());//輸出:int
        System.out.println(c2.getName());//輸出:java.lang.String
        //獲取不包含包名的類的全稱
        System.out.println(c2.getSimpleName());//輸出:String
        
    }
}

Class類的基本API操作

獲取類的全部信息,包括類的成員函數、成員變量

 1 public class ClassUtil {
 2 
 3     /**
 4      * 
 5      * @description 打印類的信息,包括類的成員函數、成員變量
 6      * @date 2016-3-28 下午5:12:42 
 7      * @param @param obj 該對象所屬類的信息
 8      * @return void
 9      */
10     public static void printClassMessage(Object obj){
11         //要獲取類的信息,首先要獲取類的類類型
12         Class c = obj.getClass();//傳遞的是哪個子類的對象,c就是該子類的類類型
13         //獲取類的名稱
14         System.out.println("類的名稱是:"+c.getName());
15         //在Java中,方法是Method類的對象
16         /**
17          * Method類,是方法的對象
18          * 一個成員方法就是一個Method的對象
19          * Method類中封裝了對方法的操作
20          * getMethods()方法獲取的是所有public的函數,包括父類繼承而來的
21          * getDeclaredMethods()獲取的是所有該類自己聲明的方法,不問訪問權限
22          */
23         Method[] methods = c.getMethods();
24         Method[] declaredMethods = c.getDeclaredMethods();
25         for(int i=0;i<methods.length;i++){
26             //得到方法的名稱
27             System.out.print(methods[i].getName()+"(");
28             //獲得參數類型--->得到的參數列表的類型的類類型
29             Class[] parameterTypes = methods[i].getParameterTypes();
30             for(Class class1 : parameterTypes){
31                 System.out.print(class1.getName()+",");
32             }
33             System.out.print(")");
34             //得到方法的返回值類型的類類型
35             Class returnType = methods[i].getReturnType();//如果方法返回得到的是int,那結果就是int.class
36             System.out.println("方法的返回值類型名稱:"+returnType.getName());//這個得到的就是名稱int
37         }
38     }
39 }

測試類:

 1 public class ClassDemo3 {
 2     public static void main(String[] args) {
 3         String s="Hello";
 4         ClassUtil.printClassMessage(s);
 5         
 6         System.out.println("=================================");
 7         Integer i=1;
 8         ClassUtil.printClassMessage(i);
 9     }
10 }

 運行結果:

  1 類的名稱是:java.lang.String
  2 hashCode()方法的返回值類型名稱:int
  3 compareTo(java.lang.Object,)方法的返回值類型名稱:int
  4 compareTo(java.lang.String,)方法的返回值類型名稱:int
  5 indexOf(java.lang.String,int,)方法的返回值類型名稱:int
  6 indexOf(java.lang.String,)方法的返回值類型名稱:int
  7 indexOf(int,)方法的返回值類型名稱:int
  8 indexOf(int,int,)方法的返回值類型名稱:int
  9 equals(java.lang.Object,)方法的返回值類型名稱:boolean
 10 toString()方法的返回值類型名稱:java.lang.String
 11 charAt(int,)方法的返回值類型名稱:char
 12 codePointAt(int,)方法的返回值類型名稱:int
 13 codePointBefore(int,)方法的返回值類型名稱:int
 14 codePointCount(int,int,)方法的返回值類型名稱:int
 15 compareToIgnoreCase(java.lang.String,)方法的返回值類型名稱:int
 16 concat(java.lang.String,)方法的返回值類型名稱:java.lang.String
 17 contains(java.lang.CharSequence,)方法的返回值類型名稱:boolean
 18 contentEquals(java.lang.StringBuffer,)方法的返回值類型名稱:boolean
 19 contentEquals(java.lang.CharSequence,)方法的返回值類型名稱:boolean
 20 copyValueOf([C,int,int,)方法的返回值類型名稱:java.lang.String
 21 copyValueOf([C,)方法的返回值類型名稱:java.lang.String
 22 endsWith(java.lang.String,)方法的返回值類型名稱:boolean
 23 equalsIgnoreCase(java.lang.String,)方法的返回值類型名稱:boolean
 24 format(java.lang.String,[Ljava.lang.Object;,)方法的返回值類型名稱:java.lang.String
 25 format(java.util.Locale,java.lang.String,[Ljava.lang.Object;,)方法的返回值類型名稱:java.lang.String
 26 getBytes(java.nio.charset.Charset,)方法的返回值類型名稱:[B
 27 getBytes()方法的返回值類型名稱:[B
 28 getBytes(java.lang.String,)方法的返回值類型名稱:[B
 29 getBytes(int,int,[B,int,)方法的返回值類型名稱:void
 30 getChars(int,int,[C,int,)方法的返回值類型名稱:void
 31 intern()方法的返回值類型名稱:java.lang.String
 32 isEmpty()方法的返回值類型名稱:boolean
 33 lastIndexOf(java.lang.String,)方法的返回值類型名稱:int
 34 lastIndexOf(int,)方法的返回值類型名稱:int
 35 lastIndexOf(int,int,)方法的返回值類型名稱:int
 36 lastIndexOf(java.lang.String,int,)方法的返回值類型名稱:int
 37 length()方法的返回值類型名稱:int
 38 matches(java.lang.String,)方法的返回值類型名稱:boolean
 39 offsetByCodePoints(int,int,)方法的返回值類型名稱:int
 40 regionMatches(int,java.lang.String,int,int,)方法的返回值類型名稱:boolean
 41 regionMatches(boolean,int,java.lang.String,int,int,)方法的返回值類型名稱:boolean
 42 replace(char,char,)方法的返回值類型名稱:java.lang.String
 43 replace(java.lang.CharSequence,java.lang.CharSequence,)方法的返回值類型名稱:java.lang.String
 44 replaceAll(java.lang.String,java.lang.String,)方法的返回值類型名稱:java.lang.String
 45 replaceFirst(java.lang.String,java.lang.String,)方法的返回值類型名稱:java.lang.String
 46 split(java.lang.String,int,)方法的返回值類型名稱:[Ljava.lang.String;
 47 split(java.lang.String,)方法的返回值類型名稱:[Ljava.lang.String;
 48 startsWith(java.lang.String,int,)方法的返回值類型名稱:boolean
 49 startsWith(java.lang.String,)方法的返回值類型名稱:boolean
 50 subSequence(int,int,)方法的返回值類型名稱:java.lang.CharSequence
 51 substring(int,)方法的返回值類型名稱:java.lang.String
 52 substring(int,int,)方法的返回值類型名稱:java.lang.String
 53 toCharArray()方法的返回值類型名稱:[C
 54 toLowerCase()方法的返回值類型名稱:java.lang.String
 55 toLowerCase(java.util.Locale,)方法的返回值類型名稱:java.lang.String
 56 toUpperCase()方法的返回值類型名稱:java.lang.String
 57 toUpperCase(java.util.Locale,)方法的返回值類型名稱:java.lang.String
 58 trim()方法的返回值類型名稱:java.lang.String
 59 valueOf([C,)方法的返回值類型名稱:java.lang.String
 60 valueOf(int,)方法的返回值類型名稱:java.lang.String
 61 valueOf(long,)方法的返回值類型名稱:java.lang.String
 62 valueOf(float,)方法的返回值類型名稱:java.lang.String
 63 valueOf(double,)方法的返回值類型名稱:java.lang.String
 64 valueOf(java.lang.Object,)方法的返回值類型名稱:java.lang.String
 65 valueOf(char,)方法的返回值類型名稱:java.lang.String
 66 valueOf([C,int,int,)方法的返回值類型名稱:java.lang.String
 67 valueOf(boolean,)方法的返回值類型名稱:java.lang.String
 68 wait()方法的返回值類型名稱:void
 69 wait(long,int,)方法的返回值類型名稱:void
 70 wait(long,)方法的返回值類型名稱:void
 71 getClass()方法的返回值類型名稱:java.lang.Class
 72 notify()方法的返回值類型名稱:void
 73 notifyAll()方法的返回值類型名稱:void
 74 =================================
 75 類的名稱是:java.lang.Integer
 76 hashCode()方法的返回值類型名稱:int
 77 reverseBytes(int,)方法的返回值類型名稱:int
 78 compareTo(java.lang.Object,)方法的返回值類型名稱:int
 79 compareTo(java.lang.Integer,)方法的返回值類型名稱:int
 80 equals(java.lang.Object,)方法的返回值類型名稱:boolean
 81 toString(int,int,)方法的返回值類型名稱:java.lang.String
 82 toString(int,)方法的返回值類型名稱:java.lang.String
 83 toString()方法的返回值類型名稱:java.lang.String
 84 toHexString(int,)方法的返回值類型名稱:java.lang.String
 85 decode(java.lang.String,)方法的返回值類型名稱:java.lang.Integer
 86 valueOf(java.lang.String,)方法的返回值類型名稱:java.lang.Integer
 87 valueOf(java.lang.String,int,)方法的返回值類型名稱:java.lang.Integer
 88 valueOf(int,)方法的返回值類型名稱:java.lang.Integer
 89 reverse(int,)方法的返回值類型名稱:int
 90 byteValue()方法的返回值類型名稱:byte
 91 doubleValue()方法的返回值類型名稱:double
 92 floatValue()方法的返回值類型名稱:float
 93 intValue()方法的返回值類型名稱:int
 94 longValue()方法的返回值類型名稱:long
 95 shortValue()方法的返回值類型名稱:short
 96 parseInt(java.lang.String,)方法的返回值類型名稱:int
 97 parseInt(java.lang.String,int,)方法的返回值類型名稱:int
 98 bitCount(int,)方法的返回值類型名稱:int
 99 getInteger(java.lang.String,)方法的返回值類型名稱:java.lang.Integer
100 getInteger(java.lang.String,int,)方法的返回值類型名稱:java.lang.Integer
101 getInteger(java.lang.String,java.lang.Integer,)方法的返回值類型名稱:java.lang.Integer
102 highestOneBit(int,)方法的返回值類型名稱:int
103 lowestOneBit(int,)方法的返回值類型名稱:int
104 numberOfLeadingZeros(int,)方法的返回值類型名稱:int
105 numberOfTrailingZeros(int,)方法的返回值類型名稱:int
106 rotateLeft(int,int,)方法的返回值類型名稱:int
107 rotateRight(int,int,)方法的返回值類型名稱:int
108 signum(int,)方法的返回值類型名稱:int
109 toBinaryString(int,)方法的返回值類型名稱:java.lang.String
110 toOctalString(int,)方法的返回值類型名稱:java.lang.String
111 wait()方法的返回值類型名稱:void
112 wait(long,int,)方法的返回值類型名稱:void
113 wait(long,)方法的返回值類型名稱:void
114 getClass()方法的返回值類型名稱:java.lang.Class
115 notify()方法的返回值類型名稱:void
116 notifyAll()方法的返回值類型名稱:void
View Code  

四、獲取成員變量、構造函數信息

 1 public class ClassUtil {
 2 
 3     /**
 4      * 
 5      * @description 打印類的成員函數的信息
 6      * @date 2016-3-28 下午5:12:42 
 7      * @param @param obj 該對象所屬類的信息
 8      * @return void
 9      */
10     public static void printClassMethodMessage(Object obj){
11         //要獲取類的信息,首先要獲取類的類類型
12         Class c = obj.getClass();//傳遞的是哪個子類的對象,c就是該子類的類類型
13         //獲取類的名稱
14         System.out.println("類的名稱是:"+c.getName());
15         //在Java中,方法是Method類的對象
16         /**
17          * Method類,是方法的對象
18          * 一個成員方法就是一個Method的對象
19          * Method類中封裝了對方法的操作
20          * getMethods()方法獲取的是所有public的函數,包括父類繼承而來的
21          * getDeclaredMethods()獲取的是所有該類自己聲明的方法,不問訪問權限
22          */
23         Method[] methods = c.getMethods();
24         Method[] declaredMethods = c.getDeclaredMethods();
25         for(int i=0;i<methods.length;i++){
26             //得到方法的名稱
27             System.out.print(methods[i].getName()+"(");
28             //獲得參數類型--->得到的參數列表的類型的類類型
29             Class[] parameterTypes = methods[i].getParameterTypes();
30             for(Class class1 : parameterTypes){
31                 System.out.print(class1.getName()+",");
32             }
33             System.out.print(")");
34             //得到方法的返回值類型的類類型
35             Class returnType = methods[i].getReturnType();//如果方法返回得到的是int,那結果就是int.class
36             System.out.println("方法的返回值類型名稱:"+returnType.getName());//這個得到的就是名稱int
37         }
38     }
39 
40     /**
41      * @description 打印類的成員變量的信息
42      * @date 2016-3-29 上午9:32:58 
43      * @param @param obj 該對象所屬類的信息
44      * @return void
45      */
46     public static void printClassFieldMessage(Object obj) {
47         //要獲取類的信息,首先要獲取類的類類型
48         Class c = obj.getClass();//傳遞的是哪個子類的對象,c就是該子類的類類型
49         /**
50          * 成員變量也是對象
51          * 它是java.lang.reflect.Field的對象
52          * Field類封裝了關於成員變量的操作
53          * getFields()方法獲取的是所有的public的成員變量的信息
54          * getDeclaredFields()方法獲取的是該類自己聲明的成員變量信息,不問訪問權限
55          */
56         Field[] fields = c.getFields();//public的成員變量用的比較少
57         Field[] declaredFields = c.getDeclaredFields();
58         for(Field field:declaredFields){
59             //得到成員變量的類型的類類型
60             Class fieldType = field.getType();
61             String typeName = field.getName();
62             //得到成員變量的名稱
63             String fieldName = field.getName();
64             System.out.println(typeName+" "+fieldName);
65         }
66     }
67     
68     /**
69      * 
70      * @description 打印對象的構造函數信息
71      * @date 2016-3-29 上午9:39:50 
72      * @param @param obj 該對象所屬類的信息
73      * @return void
74      */
75     public static void printClassConstructorMessage(Object obj){
76         //要獲取類的信息,首先要獲取類的類類型
77         Class c = obj.getClass();//傳遞的是哪個子類的對象,c就是該子類的類類型
78         /**
79          * 構造函數也是對象
80          * 它是java.lang.reflect.Constructor的對象
81          * Constructor類中封裝了構造函數的信息
82          * getConstructors()獲取所有public的構造函數
83          * getDeclaredConstructors()獲取的是該類自己聲明的所有的構造函數
84          * 構造方法是沒有返回值類型的
85          */
86         Constructor[] constructors = c.getConstructors();
87         Constructor[] declaredConstructors = c.getDeclaredConstructors();
88         for (Constructor constructor : declaredConstructors) {
89             System.out.print(constructor.getName()+"(");
90             //獲取構造函數的參數列表--->得到的是參數列表的類類型
91             Class[] parameterTypes = constructor.getParameterTypes();
92             for (Class class1 : parameterTypes) {
93                 System.out.print(class1.getName()+",");
94             }
95             System.out.println(")");
96         }
97     }
98 }

測試類:

 1 /**
 2  * @description 測試ClassUtil類的操作
 3  * @date 2016-3-28 下午5:34:47 
 4  */
 5 public class ClassDemo3 {
 6     public static void main(String[] args) {
 7         System.out.println("=========獲取類的成員函數的信息========================");
 8         //測試獲取類的成員方法的信息
 9         String s="Hello";
10         ClassUtil.printClassMethodMessage(s);
11         
12         Integer i=1;
13         ClassUtil.printClassMethodMessage(i);
14         
15         System.out.println("=========獲取類的成員變量的信息========================");
16         //測試獲取類的成員變量的信息
17         Integer i1=1;
18         ClassUtil.printClassFieldMessage(i);
19         
20         System.out.println("=========獲取類的構造函數的信息========================");
21         ClassUtil.printClassConstructorMessage("Hello");
22         ClassUtil.printClassConstructorMessage(new Integer(1));
23     }
24 }

注意:要獲取類的信息,首先要獲取類的類類型。obj.getClass()  

五、方法的反射

1、如何獲取某個方法

方法的名稱和方法的參數列表才能唯一決定某個方法

2、方法反射的操作

method.invoke(對象,參數列表)

 1 public class MethodDemo1 {
 2     public static void main(String[] args) {
 3         /**思考:如何獲得方法對象,然後用方法對象進行反射操作
 4          * 1、要獲取一個方法首先要獲取類的信息,獲取類的信息首先要獲取類的類類型
 5          * 2、獲取方法必須要有名稱和參數列表來決定
 6          */
 7         //1、首先要獲取類的信息,獲取類的信息首先要獲取類的類類型
 8         A a1=new A();
 9         Class c = a1.getClass();
10         
11         /*2、獲取方法 名稱和參數列表來決定
12          * getMethod獲取的是public的方法
13          * getDeclaredMethod()獲取自己聲明的方法
14          */
15         try {
16             //獲取print(int,int)方法.
17             System.out.println("=================獲取print(int,int)===============");
18             //這個一定會拋出異常,我們這裡簡單的處理一下異常,原因:萬一這個方法(帶兩個整型參數的方法)不存在呢
19             Method method = c.getMethod("print", new Class[]{int.class,int.class});//這個方法中“...”代表可變參數,當有幾個參數的時候,可以new Class數組
20             //也可以這樣寫:有幾個參數就傳幾個參數
21             Method method2 = c.getMethod("print", int.class,int.class);
22             a1.print(10, 20);//普通調用(可以理解為a1這個對象操作方法對象print)
23             /*方法的反射操作是用method/method2對象來進行方法調用 和a1.print()調用的效果完全相同
24              *方法如果沒有返回值,返回null。有返回值就返回具體的返回值如下面的Object o
25              */
26             Object o = method.invoke(a1, new Object[]{10,20});//方法的反射(可以理解為print這個方法對象,即method/method2來操作a1,即上面普通調用反過來操作,通過invoke來進行操作)
27             //也可以這樣:
28             Object o1 = method.invoke(a1, 10,20);
29             
30             
31             
32             System.out.println("=================獲取print(String,String)===============");
33             //獲取方法print(String,String)
34             Method method3 = c.getMethod("print", String.class,String.class);
35             a1.print("hello", "world");//普通調用
36             //對方法進行反射操作
37             Object o2 = method3.invoke(a1, "hello","world");
38             
39             
40             
41             
42             System.out.println("=================獲取print()無參方法===============");
43 //            Method method4 = c.getMethod("print", new Class[]{});
44             Method method5 = c.getMethod("print");//沒有參數就不傳
45 //            method5.invoke(a1, new Object[]{});
46             method5.invoke(a1);
47         }catch (Exception e) {
48             e.printStackTrace();
49         }
50     }
51 }
52 
53 class A{
54     public void print(){
55         System.out.println("hello world");
56     }
57     public void print(int a,int b){
58         System.out.println(a+b);
59     }
60     public void print(String a,String b){
61         System.out.println(a.toUpperCase()+","+b.toUpperCase());
62     }
63 }

六、通過反射了解集合泛型的本質

通過Class、Method來認識集合泛型的本質

 1 public class MethodDemo2 {
 2     public static void main(String[] args) {
 3         ArrayList list=new ArrayList();
 4         
 5         ArrayList<String> list1 = new ArrayList<String>();
 6         list1.add("hello");
 7 //        list1.add(20);//傳個整型,就是錯誤的
 8         
 9         Class c1 = list.getClass();
10         Class c2 = list1.getClass();
11         System.out.println(c1==c2);//true
12         /**
13          * 分析:
14          * Class,我們可以認為是類類型或字節碼,因為文件編譯之後就生成*.class文件
15          * 也就是說:反射的操作(Class、Method、field的操作)都是編譯之後的操作(就是變成字節碼之後的操作)就是在運行時刻執行的
16          * 
17          * c1==c2結果返回true說明編譯之後集合的泛型是去泛型化的
18          * Java中集合的泛型,是防止錯誤輸入的,只在編譯階段有效,繞過編譯就無效了
19          * 驗證:我們可以通過方法的反射來操作,繞過編譯
20          */    
21         try {
22             Method method = c2.getMethod("add", Object.class);//參數是Object類型,沒有任何的泛型類型
23             method.invoke(list1,20);//繞過了編譯就繞過了泛型
24             System.out.println(list1.size());//輸出size為2,說明整型20加進去list1集合裡面了
25             System.out.println(list1);//輸出[hello, 20]
26             //不能再用foreach進行遍歷了,這時他認為都是String類型,會報異常:java.lang.ClassCastException,會提示說int類型不能轉換成String類型
27             /*for (String string : list1) {
28                 System.out.println(string);
29             }*/
30         } catch (Exception e) {
31             e.printStackTrace();
32         } 
33     }
34 }

 

Copyright © Linux教程網 All Rights Reserved