反射

来源:互联网 发布:java基础常见面试题 编辑:程序博客网 时间:2024/06/07 14:37

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

 

反射

      Java程序中的各个Java类属于同一类事物,描述这类事物的Java类名就是Class

      对比提问:众多的人用一个什么类表示?众多的Java类用一个什么类表示?

                Person java    Class

      对比提问:Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class类代表Java类,它的各个事例对象又分别对应   什么呢?

             对应各个类的字节码,如Person类的字节码,ArrayList类的字节码等等

             一个类被类加载器加载进入内存中,占用了一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码不同,所以它们在内存             中的内容是不同的

             这一个个空间可分别用一个个的对象来表示,这些对象显然具有相同的类型。

      如何得到各个字节码对象的事例对象(Class类型)

             1、类名.class,如:System.class

             2、对象.getClass(),如:new Date().getClass()

             3Class.forName("类名");,如:Class.forName("java.lang.String");

      九个预定义Class实例对象:

             八个基本数据类型(boolean,char,byte,short,int,lang,float,double

      数组类型的Class实例对象:

             class.isArray()

             总之,只要在源程序中出现的类型,都有各自的Class实例对象,如:int[]void

       如:

  1. package cn.itcast.day1;  
  2.   
  3. public class ReflectTest {  
  4.   
  5.     /** 
  6.      * @param args 
  7.      */  
  8.     public static void main(String[] args)throws Exception {  
  9.         // TODO Auto-generated method stub  
  10.         String str1 = "abc";  
  11.         Class cla1 = str1.getClass();  
  12.         Class cla2 = String.class;  
  13.         Class cla3 = Class.forName("java.lang.String");  
  14.         //验证三种方法是不是同一份字节码,答案都是true  
  15.         System.out.println(cla1==cla2);  
  16.         System.out.println(cla1==cla3);  
  17.           
  18.         System.out.println(cla1.isPrimitive());//判断是否是一个基本数据类型  
  19.         System.out.println(int.class==Integer.class);//intInteger是不同类型,各自有自己的字节码  
  20.         System.out.println(int.class==Integer.TYPE);//TYPE用来表示所包装的那份基本类型的字节码  
  21.         //数组出现的类型也有自己的字节码,用isArray()判断  
  22.         System.out.println(int[].class.isPrimitive());  
  23.         System.out.println(int[].class.isArray());  
  24.           
  25.     }  
  26.   

 

      反射概念:就是把JAVA类中的各种成分映射成相应的JAVA类。

       如:一个java类中用一个Class类的对象来表示,一个类中的组成部分:成员变量,方法,构造方法,包等等信息也用一个个的JAVA类来表示,就像汽车是一个类,汽车的发动机,变速箱等等也是一个个类。表示java类的Class类显然就是提供一系列方法,来获得其中的变量,方法和构造方   法,修饰符,包等等信息,这个信息就是用相应类的事例对象来表示,它们是FieldMethodConstructorPackage等等。

 

      Constructor类:

           1、概述:Constructor代表某个类的构造方法。

           2、获取构造方法:

                 1、如何得到某个类的所有构造方法(如得到String类的所有构造方法):

                      Constructor[] cons = Class.forName(“java.lang.String”).getConstructors()

                 2、获取某一个构造方法:

                      Constructor con =String.class.getConstructor(StringBuffer.class);        

            3、创建实例对象:

                 1、通常方式:String str = new String(new StringBuffer (”abc”));

                 2、反射方式:String str = (String)con.newInstance(new StringBuffer(“abc”)); 

             调用获得的方法时要用到上面相同类型的实例对象,即两个StringBuffer()要对应相等。

             NewInstance():构造出一个实例对象,每调用一次就构造一个对象。

             注意:上面的两个地方①②都要用到StringBuffer,这必须是一致的。

             个是指定要带StringBuffer参数类型的构造方法,即所需使用的是含StringBuffer类型的构造方法。

             个是用这个构造方法创建对象,要传入的参数类型必须是StringBuffer

             4、Class.newInstance():创建一个对象,不带参数的构造方法。

     

      Field类:

                            概述:Field类代表成员变量(字段)的反射。

                           如:

  1. public class ReflectPoint {  
  2.     private int x;  
  3.     public int y;  
  4.   
  5.     public String toString(){  
  6.         return str1+";" + str2 + ";" + str3;  
  7.     }  
  8. }  
  9. public class FieldTest(){  
  10. ReflectPoint pt1 = new ReflectPoint(3,5);  
  11.     //fieldXfieldY并不是对象身上的变量,而是类上的  
  12.     //要用它去取某个对象上的对应的值,传入什么对象,就取相应对象的值。  
  13.     Field fieldY = pt1.getClass().getField("y");  
  14.     System.out.println(fieldY.get(pt1));  
  15.     //获取私有的成员变量  
  16. Field fieldX = pt1.getClass().getDeclaredField("x");  
  17.     fieldX.setAccessible(true);  
  18.     System.out.println(fieldX.get(pt1));  

 

           Method类:

                 1、概述:Method类代表某个类中的一个成员方法。调用某个对象身上的方法,要先得到方法,再针对某个对象调用。

                 2、专家模式:谁调用这个数据,就是谁在调用它的专家。

                 如人关门。调用者:是门调用管的动作,对象是门,因为门知道如何执行关的动作,通过门轴之类的细节实现。指挥者:是人在指挥门做              关的动作,只是给门发出了关的信号,让门执行。

                 总结:变量使用方法,是方法本身知道如何实现执行的过程,也就是方法对象调用方法,才执行了方法的每个细节的。

                 3、获取某个类中的某个方法:(如String str = ”abc”

                         1、通常方式:str.charAt(1)

                         2、反射方式:

                                 Method charAtMethod = Class.forName(“java.lang.String”).getMethod(“charAt”,int.class);

                                 charAtMethod.invoke(str,1);

                                 说明:如果传递给Method对象的invoke()方法的第一个参数为null,说明Method对象对应的是一个静态方法

                  4、用反射方式执行某个main方法:

                          首先要明确为何要用反射:在写源程序时,并不知道使用者传入的类名是什么,但是虽然传入的类名不知道,而知道的是这个类中                          的方法有main这个方法,所以可以通过反射的方式,通过使用者传入的类名(可定义字符串型变量作为传入类名的入口,通过这个                          变量代表类名),内部通过传入的类名获取其main方法,然后执行相应的内容。

                如:

  1. //Method类演示  
  2. private static void methodTest(String [] args) throws Exception {  
  3.     String str1 = "abc";  
  4.     //一般方法:  
  5.     System.out.println(str1.charAt(1));  
  6.     //反射方法   
  7.     Method methodCharAt =  
  8.         Class.forName("java.lang.String").getMethod("charAt",int.class);  
  9.     System.out.println(methodCharAt.invoke(str1,1));  
  10.       
  11.     //用反射方式执行某个main方法  
  12.     //一般方式:  
  13.     Test.main(new String[]{"111","222","333"});  
  14.     System.out.println("-------");  
  15.       
  16.     //反射方式:  
  17.     String startingClassName = args[0];  
  18.     Method methodMain =  
  19.         Class.forName(startingClassName).getMethod("main",String[].class);  
  20.         //方案一:强制转换为超类Object,不用拆包  
  21.         methodMain.invoke(null,(Object)new String[]{"111","222","333"});  
  22.         //方案二:将数组打包,编译器拆包后就是一个String[]类型的整体  
  23.         methodMain.invoke(null,new Object[]{new String[]{"111","222","333"}});  
  24.     }  
  25. //定义一个测试类  
  26. class Test{  
  27.     public static void main(String [] args){  
  28.         for(String arg : args){  
  29.             System.out.println(arg);  
  30.         }  
  31.     }  
  32. }

 

           数组的反射:

                具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)

                代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class

                基本类型的一维数组可以被当作Object类型使用,不能当作Object[]类型使用;非基本类型的一维数组,既可以当做Object类型使用,又               可以当做Object[]类型使用。

                Arrays.asList()方法处理int[]String[]时的差异。

                Array工具类用于完成对数组的反射操作。

 

---------------------- ASP.Net+Android+IOS开发、.Net培训、期待与您交流! ----------------------

0 0