---------------------- 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 , getDeclareMethods和getDeclareConstructors方法返回类中声明的全部字段,方法和构造函数,包含私有的和受保护的,但是不包括父类的成员
下面就来说说这么反射这些类的成分.
方法的反射: Method
方法的反射使用的是Method类,要得到Method的对象,首先要得到一个Class,然后通过Class的getMethod()
或getMethods()
方法得到一个method. getMethod()是得到一个方法, getMethods是得到所有的方法,用数组表示
例如: Method method= Class.forName().getMethod(name, parameterTypes);
如果第一个参数为null,则说明这个方法是静态的
Method [] methods= Class .forName() .getMethods ();
Method对象的常用方法有:
getName()以 | |
|
|
invoke(Object obj,Object... args) | |
|
|
严重注意:
当一个方法的参数类型是数组类型的时候,按照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,然后通过Class的getField
()
或getFields
()
方法得到一个Field.getField
()是得到一个方法,getFields
是得到所有的方法,用数组表示
Field对象常用的方法有:
getName() | |
Class<?> | getType() |
void | set(Object obj,Object value) |
Class<?> | getDeclaringClass() |
要获取某个对象中的字段.可以这样:
Person p = new Person(3, 5); //Person中有两个字段 ,x和y , 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,然后通过Class的getConstructor
()
或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<?> | |
getConstructor(Class<?>... parameterTypes) | |
Constructor<?>[] | getConstructors() |
newInstance() |
使用反射创建一个对象
得到Class对象à通过Class对象得到对应的Constructorà通过Constructor的newInstance创建对象
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