黑马程序员-java基础-反射

来源:互联网 发布:淘宝私人订制板块在哪 编辑:程序博客网 时间:2024/06/06 08:58

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、java反射机制
这部分是我接触java以来感觉最难的一部分了,反复看了几次资料都有点似懂非懂的感觉,我觉的要理解java首先要理解Class这个类,注意这个Class是一个类,而不是关键字class,因为这个类是一个对java中所有类进行描述的一个类,也就是说java把java中的类看作了同一个事物,就使用了Class这个类名定义了一个专门用于描述java类的特殊类。JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。而这些被调用的类,也就是加载到内存中的字节码文件就是一个个Class的实例对象了。而这类中的方法,变量等成份也都被映射成了java中的Method和Field等类!总得来说,java的映射就是将java类中的成份映射成了一个个java中的类。而获取Class类实例对象的方法有三种:

第一种:通过“类名.class”的方式
        任何数据类型都具备着一个静态的属性class,这个属性直接获取到该类型的对应Class对象。如:Class clazz=Person.class;//Person是一个类名,不用创建对象,不用调用getClass方法,但是还是要使用具体的类,和该类中的一个静态属性class完成。

第二种:通过“对象.getClass()方法获取”
        通过对象的getClass方法进行获取。如:Class clazz=new Person().getClass();//Person是一个类名麻烦之处:每次都需要具体的类和该类的对象,以及调用getClass方法。

第三种:通过Class类的静态方法forName()获取:
        这种方式较为简单,只要知道类的名称即可。不需要使用该类,也不需要去调用具体的属性和行为。就可以获取到Class对象了。如:Class clazz=Class.forName("包名.Person");//Person是一个类名,这种方式仅知道类名就可以获取到该类字节码对象的方式,更有利于扩展。所以中中方式是在开发中是比较常用的。

二、Class类中一些重要的方法
1、在获取到Class的对象之后我们就可以只用其中的一些方法了对该对象(字节码文件)进行一系列的操作了,首先要说到的就是那个getConstructors()方法了。我们知道java的映射就是将java类中的成份映射成了一个个java中的类。所以java类中的构造方法也有想对应的类对他进行描述(反射),这个类就是Constructor。getConstructor(Class<?>... parameterTypes) ,通过参数的传递可以返回Class对象中对应的公共构造方法。而不带参数的则是返回了Class对象所对应类中所有的构造方法,使用Constructor[]类型的数组进行存放即可。下面通过小例子演示,是java中比较常用于实际开发中的,其它的方可以通过API查看:

<span style="font-size:14px;">class Test{public static void main(String[] args)throws Exception{//获取String的字节码文件,也就是Class对应String的对象Class cla = Class.forName("java.lang.String");//获取cla对象对应的String中所有的构造方法,并存如到Constructor类型的数组中。Constructor[] coss = cla.getConstructors();//获取String类中对应参数类型的构造方法。Constructor constructor = cla.getConstructor(StringBuffer.class);//下面使用获取到的构造方法创建一个String类型的对象。//普通方法:String string = new String(new StringBuffer("hello"));//使用反射的原理String string = (String)constructor.newInstance(new StringBuffer("hello"));//上面要注意的是newInstance()方法定义的形式参数是Object类型的,所以这里是需要进行强转的System.out.println(string.charAt(1));//打印第二个字符}}</span>


2、上面我们已经通过getConstructor()方法获取到了某个类中的构造方法,并使用newInstance()方法成功的建立了String的一个对象,那么获得这些对象后不免要对里面的成员变量等元素进行操作,那么我们又同过什么方法去获得这些成员变量呢?这就是接下来所要介绍的一个类了:Field这个类就是专门用来描述java类中的成员变量的,而某个类中的字段我们是可以通过Class类中的getFiled(String name)方法来获取的。下面看个小例子:

<span style="font-size:14px;">calss Demo{public int y;private int x;Demo(int x ,int y){this.x = x;this.y = y;}}//实现反射class ReflectedDemo{public static void main(String[] args){//使用普通的方法对x,y进行初始化Demo demo = new Demo(3,5);//下面就是用反射的方式修改demo对象中的值//获取Demo的字节码文件(Class对象)Class cla = Demo.calss;//获得Demo中指定字段的对象Filed fy = cla.getFiled("y");fy.set(demo,6)//这里的fy可以表示所有Demo类所产出来的对象的y,所以当使用set()方法//对y赋值的时候必须指明操作那个对象上的y,值是多少。fy.get(demo);//获取demo对象中y的值//当然我们要想通过反射的方式获取demo对象中x的值也可以是用getFiled("x")的方式获取x字段的Filed对象}}</span>

这里要注意的是getFiled()这个方法之只能返回Demo类中公共的字段对象,所以java就为了能够使用反射的方式访问私有的字段如x,提供了另个一个方法获取该字段的对象:Filed filed = Demo.class.getDeclaredField(String name) ,但是即使我们获得了该对象也依然不能对该对象对应的变量进行操作,这时使用filed.setAccessible(true)方法即可。这中方式也称为java中的暴力反射。

下面通过一个例子,演示对Filed 的具体应用
<span style="font-size:14px;">/*通过反射的原理,将Demo对象中的str1和str2中的a全部替换成b。*/calss Demo{public String str1="hahaha";public String str2="animeidea";Demo(int x ,int y){this.x = x;this.y = y;}public String toString(){return str1+":"+str2}}class Test{public static void main(String[] args){Demo demo = new Demo();Class cla = Demo.class;//获取Demo的字节码文件Filed[] fileds = cla.getFileds();for(Filed f : fileds){//判断是否为同一个字节码文件if(String.class == f.getType()){String oldValue = (String)f.get(demo);//get()方法返回的是Object类型String newValue = oldValue.replace('a','b');//替换//将替换好的字符串重新写入f.set(demo,newValue);}}System.out.println(demo.toString());}}</span>


3、java类中的构造方法,成员变量的反射都说过了,那么接下来就谈谈成员方法的反射把,在这里就涉及到了用于描述java各个类中成员方法的类了,他就是Method这个类了,这个类的对象我们是同过Class中的getMethod(String name, Class<?>... parameterTypes) 方法获取的,由于方法存在重载的形式所有该方法除了要指定方法名之外还需要指定参数列表的。当然还有getMethods()这样的获取方法列表的方法,查看api文档就可以了,下面就用一个例子去演示如果同过反射去获取String类中的charAt()方法:

<span style="font-size:14px;">class Test{public static void main(String[] args){String string = "abcde";Class  cla = String.class;//获取String的字节码文件//使用反射的方式获得String类字节码中charAt方法Method methodCharAt = cla.getMethod("charAt",int.class);//明确该方法作用与那一个对象。并明确操作对象哪个角标methoCharAt.invoke(string,1);}}</span>

三、看完这几个类的应用大概对反射有了初步的了解了,还有关于数组的反射,还有反射的具体应用,那些东西还是比较模糊,所以后期深入理解后再补上,总得来说,按照这样的规律可以知道,反射在后期的程序扩展是有非常大的好处的,当我们要调用一个还未出现的类的时候我们可以定义该类类名为一个变量,而该变量的名称可以通过扫描配置文件获得,这样当我们后期要添加新的功能类的时候直接修改配置文件就可以可以获取到该类的Class对象了,这样就可以通过反射的方式调用其内部的变量、方法等元素。

0 0