黑马程序员-学习日志10

反射(Reflection)

------- <a href="http://www.itheima.com" target="blank">android培训</a>、<a href="http://www.itheima.com" target="blank">java培训</a>、期待与您交流! ----------

反射是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对象的常用方法有:

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,然后通过Class的getField()或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中有两个字段 ,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<?>
forName(String className)
          返回与带有给定字符串名的类或接口相关联的 Class 对象。
 Constructor<T>
getConstructor(Class<?>... parameterTypes)
          返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
 Constructor<?>[]
getConstructors() 
          返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
newInstance() 
          创建此 Class 对象所表示的类的一个新实例。
使用反射创建一个对象
得到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只能在使用到哈希值的集合中才有意义,另外还有一个小注意就是,使用到哈希值的元素不要作修改,因为修改了以后,这个元素的哈希值就发生了改变,就会被存放到另一个区域中,而要删除这个元素时,是删除原区域的元素,显然,这个元素真正的值已经不在原区域了,这样一来,就会让人误认为这个元素已经删除了,其实并没有,这样一来,修改的元素多了,但是却没有释放,就会导致内存泄露
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值