• Java框架基础——反射(reflect)


    一、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  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 }
  • 相关阅读:
    android 基础项目及开发出现:error opening trace file: No such file or directory错误解决
    Android开发遇到的问题
    Don‘t talk.Just do it.
    LeetCode——Word Break
    晋IT分享成长沙龙集锦
    logback 简单配置总述
    HDU 2119 Matrix 简单二分匹配
    华为招聘机试整理5:简单四则运算
    JSP简单练习-猜字母游戏
    Codechef July Challenge 2014部分题解
  • 原文地址:https://www.cnblogs.com/Qian123/p/5329363.html
Copyright © 2020-2023  润新知