黑马程序员-反射

来源:互联网 发布:全球直播软件 编辑:程序博客网 时间:2024/06/07 01:05

 ---------------------- android培训,java培训、期待与您交流! ----------------------

 

反射(Reflection)

反射是java中一种强大的机制. Java反射机制主要提供了以下功能:

1.行时判断任意一个对象所属的类;

2.行时构造任意一个类的对象;

3.运行时判断任意一个类所具有的成员变量和方法;

4.在运行时调用任意一个对象的方法;生成动态代理。

反射简单的解释就是,把类中的成分,映射到相应的类,达到用这些类操作框架.

 

要理解反射首先要理解Class:

Java源程序到java程序运行要经历一个曲折的过程:

源程序javac编译源程序,得到.class文件jvm从硬盘读取.class文件,并且把.class文件转化成字节码存入内存读取这些字节码,得到程序运行效果

 

在第三个步骤的, jvm从硬盘读取.class文件,并且把.class文件转化成字节码存入内存,其中每一份字节码就是一个Class对象,Class相当于字节码的类(类似于Person是人的类).要得到Class,通常有3种方式:

1.       类名.class

2.       对象名.getClass()

3.       Class. forName(完整的类名);      

第三种方式在反射中比较常用.

当虚拟机里面已经有了这个字节码,那么每次需要用到这个字节码的时候,就直接到虚拟机里面找,这么一来,每次使用这个字节码的地址都是一样的

 

反射的作用是把类中的成分,映射到相应的类,也就是说类中的方法,字段,构造函数,数组等都有映射的类,它们对应的就是Method , Field, Constructor, Array

 

Class类中的getFields , getConstructors,getMethods方法返回public修饰的字段,构造函数和方法的数组,其中包括父类的公有成员.

Class类中的getDeclareFields , getDeclareMethodsgetDeclareConstructors方法返回类中声明的全部字段,方法和构造函数,包含私有的和受保护的,但是不包括父类的成员

 

下面就来说说这么反射这些类的成分.

 

方法的反射: Method

方法的反射使用的是Method,要得到Method的对象,首先要得到一个Class,然后通过ClassgetMethod()getMethods()方法得到一个method. getMethod()是得到一个方法, getMethods是得到所有的方法,用数组表示

例如: Method method= Class.forName().getMethod(name, parameterTypes);

如果第一个参数为null,则说明这个方法是静态的

        Method [] methods= Class .forName() .getMethods ();

Method对象的常用方法有:

String

getName()String形式返回此Method对象表示的方法名称。

Class<?>[]

getParameterTypes()按照声明顺序返回Class对象的数组,这些对象描述了此Method对象所表示的方法的形参类型。

Object

invoke(Object obj,Object... args)
          对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

 

 

严重注意:

       当一个方法的参数类型是数组类型的时候,按照jdk1.5的语法,整个数组就是一个参数,但是按照jdk1.4的语法,数组中的每一个元素都对应一个参数, javac会按照jdk1.4的语法来编译,这么一来,参数列表的参数个数就不匹配了.

       解决方法:

1.       在数组的外层再包裹一个object数组,这么一来,编译的时候,javac拆包只拆外层的object数组,内层的数组就得以完整的作为参数传递给方法了

MainMethod .invoke( null, new Object[] {new String [] {“xxxx”}});

2.       在数组前面加上(object),意在告诉编译器,这是一个对象,不是一个数组,不需要拆包

MainMethod .invoke( null, (Object) new String [] {“xxxx”});

 

 

字段的反射:Field

与方法的反射一样,要得到Field对象,首先要得到一个Class,然后通过ClassgetField()getFields()方法得到一个Field.getField ()是得到一个方法,getFields是得到所有的方法,用数组表示

 

Field对象常用的方法有:

 Object

get(Object obj)
          返回指定对象上此 Field 表示的字段的值。

String

getName()
          返回此 Field 对象表示的字段的名称。

Class<?>

getType()
          返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。

 void

set(Object obj,Object value)
          将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

 Class<?>

getDeclaringClass()
          返回表示类或接口的 Class 对象,该类或接口声明由此 Field 对象表示的字段。

要获取某个对象中的字段.可以这样:

Person  p = new Person(3, 5);    //Person中有两个字段 ,xy , x为私有字段 , y为公有字段

Filed  f  =    p . getClass( ) . getFiled(“y”);              //得到Person类在字节码中的y字段

f . get(p);                                                               //得到p对象的y字段

 

但是私有字段不能这样拿到,需要换一种方式:

File  f= p . getClass() . getDeclaredFiled ( “x” ); //获取到字节码中的私有字段

f . setAccessible ( true );                            //强制访问这个私有字段

f . get(p);                                                 //得到p对象的私有字段x

 

 

构造函数的反射:Constructor

同上,要得到Constructor 对象,首先要得到一个Class,然后通过ClassgetConstructor()getConstructors()方法得到一个Field.getConstructor ()是得到一个方法,getConstructors是得到所有的方法,用数组表示

 

              要获取某个对象中的字段.可以这样:

Constructor [ ] con = Class . forName(“”) . getConstructors();

              要得到某个类中所有的构造方法,可以这样:

              Constructor  con  =  Class . forName(“”) . getConstruct(构造方法的参数);

要创建实例对象:

              通常方式:     

String str = new String( new StringBuffer( “ abc” ));

反射方式:

              //得到一个构造方法对象

       Constructor con=String.class.getConstructor(new StringBuffer(“abc”));

              //使用这个构造方法对象创建String实例

              String str= (String)con . newInstance(new StringBuffer( “abc” ));

 

       Class.newInstance()方法:该方法内部先得到默认的构造方法,然后用该构造方法创建实例对象

例如:      String str=(String)Class.forName(“java.lang.String”).newInstance();

 

Constructor对象的常用方法有:

static Class<?>

forName(String className)
          返回与带有给定字符串名的类或接口相关联的 Class 对象。

 Constructor<T>

getConstructor(Class<?>... parameterTypes)
          返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

 Constructor<?>[]

getConstructors()
          返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

 T

newInstance()
          创建此 Class 对象所表示的类的一个新实例。

 

 

使用反射创建一个对象

得到Class对象à通过Class对象得到对应的Constructorà通过ConstructornewInstance创建对象

Constructor<String> con = String.class.getConstructor(new StringBuffer().getClass);    //要调用String的那一个构造方法,需要通过参数类型来确定

String str=con. newInstance(new StringBuffer (“ abc ”));  //通过构造方法创建实例的时候,需要给构造方法传递参数   

 

数组的反射:Array

 当数组的维度和类型都相同的时候,他们的字节码地址就是相同的

例如 : int[] intone=new int [3];

         Int [] inttwo=new int[5];

       intone.getClass()==inttwo.getClass()ààtrue

 

Object的子类中没有基本数据类型,只有基本数据类型对应的类,例如Integer,

所以Object [] obj,不能存放基本数据类型

Int [] a1=new int [3];

Int [] [] a3=new int [2] [3];

String [] s1=new String [3] ;

 

Object  o1 =a1           , a1数组的类型是int类型,会自动装箱变成Integer类型

Object  o2=s1            ,  s1不是基本数据类型,可以转换成Object

Object []  o3 =a1       因为a1中的元素是基本数据,无法转换成Object

Object []  o4 =a3       因为a3中的元素是还是一个数组,数组不是基本数据类型,所以可以转换成Object

Object []  o4 =s1       ,因为String不是基本数据类型

 

       用反射可以构建框架,框架:就是事先做好的一个结构,这个结构中的类是不确定的,要后期把具体的类放到这个框架里,框架是在调用类.框架和工具类有不同,框架是事先做好的,哪里该放什么都有规定,它是在调用工具.

 

. HashCode方法的作用:

当要存入一个元素到哈希表结构的集合中的时候,jvm会在集合中创建很多个区域,每个区域有对应的哈希值,,每一个区域都可以存放若干个元素,这样一来,要判断要存放的元素是否存在,就不用和集合中的元素一个一个比较,只要找到其哈希值对应的区域,然后比较这个区域中的元素就可以了,但是HashCode只能在使用到哈希值的集合中才有意义,另外还有一个小注意就是,使用到哈希值的元素不要作修改,因为修改了以后,这个元素的哈希值就发生了改变,就会被存放到另一个区域中,而要删除这个元素时,是删除原区域的元素,显然,这个元素真正的值已经不在原区域了,这样一来,就会让人误认为这个元素已经删除了,其实并没有,这样一来,修改的元素多了,但是却没有释放,就会导致内存泄露

 

 

---------------------- android培训,java培训、期待与您交流! ----------------------

详细请查看
http://edu.csdn.net/heima