黑马程序员_学习日记十五_基础加强之反射

本文介绍了Java反射的基础,包括Class类的获取方式,反射的概念,以及Constructor, Field, Method类在构造方法、成员变量和成员方法反射中的应用。通过反射,可以动态地获取类信息并操作类的构造方法、成员变量和成员方法,包括对接受数组参数的方法进行反射调用。" 53374417,5636171,ParaWork软件项目估算平台:智能项目管理工具,"['项目管理工具', '软件工程', '项目估算', '成本分析', '生产率分析']
摘要由CSDN通过智能技术生成

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

 

反射的基础Class类

    反射并不是java1.5中的特性,而是java1.2版本中就具备这个特性。先来了解反射所需的基础Class类。

    Java程序中的各个Java类(.class文件)属于同一类事物,描述这类事物的Java类名就是Class类。Class类十分特殊,它和一般classes一样继承自Object类,它没有公有的构造方法,不能实例化对象,当一个类被加载,或当加载器(classloader)的defineClass()被JVM调用时,JVM 便自动产生一个Class类对象。

    获取字节码文件对应的实例对象的三种方法(Class类型)

    1.类名.class。例如:System.class;

    2.对象.getClass,例如:new Person().getClass;

    3.Class.forName(“类名”),例如:Class.forName(“java.until.Date”); forName()这个方法是Class类中的一个静态方法,它返回与带有给定字符串名的类或接口相关联的Class对象。反射机制中主要运用到的就是该方法,因为在编写源程序的时候还不知道类名。

    说明:一个类源文件编译之后生成的字节码文件,通过以上三种方式获取到的实例对象是同一个。

    九种预定义的Class实例对象,包括基本的Java的八种基本数据类型(booleanbytecharshortintlongfloatdouble)和关键字voidClass对象。当获取一个未知的Class实例对象之后,可以通过isPrimitive()方法来判断该对象是否属于基本数据类型的Class实例对象

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

反射的概念

    反射就是把java中的各种成分映射成相应的java类。例如,一个java类中用一个Class类的对象来表示,一个类中的组成部分有构造方法,成员变量,成员方法,包等。这些信息也用一个java类来表示。表示java类的Class类显然要提供一系列的方法,来获取其中的构造方法,成员变量,成员方法,包等信息。这些信息就是用相应类的实例对象来表示,它们所对应的类分别是Constructor类,Filed类,Method类,Package类等。

构造方法的反射-Constructor类

    Constructor类是java.lang.reflect包中的一个类,它的实例对象代表某个类中的一个构造方法。但是这个类本身不提供构造方法,那怎么获取该类的对象呢?在Class类中,提供了用于获取Constructor类对象的方法。

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

    那么,要如何获取目标类中的指定的构造方法呢?可以通过向该方法传递参数的形式来获取这个指定的构造方法,注意:所传入的参数也必须是一个java的Class类对象。比如:

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

    2.Constructor[]getConstructors(),获取目标类中的所有公共构造方法,返回一个Constructor类对象数组。

    所以,在获取Constructor对象之前,首先要获取目标类的Class实例对象。

    获取到某个java类中的构造方法的Constructor类实例对象之后,就可以调用Constructor类中的方法来实例化对象。

    1.T newInstance(Object…),使用此Constructor对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。比如:

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

    实际上,Class类中也有一个newInstance()方法,它的内部就是调用Constructor的无参newInstance()方法,所以要想通过这种方式来创建对象一定要保证类有一个无参构造方法。

成员变量的反射-Filed类

    Field类也是java.lang.reflect包中的一个类,它的实例对象代表类中的某一个成员变量。同样,Field类不提供构造方法,要获取Field类的实例对象,同样首先要获取目标类的Class实例对象。

    1.FieldgetField(String name),返回一个Field对象,它反映此Class对象所表示的类或接口的指定公共成员字段。根据所接收的参数来指向对应的目标类中的成员变量。比如:

           Field field = 目标类对象.getClass().getField(“成员变量名”);

    2.Field[] getFields(),返回一个包含某些Field对象的数组,这些对象反映此Class对象所表示的类或接口的所有可访问公共字段。

       3.Field getDeclearedField(String name),返回一个Field对象,该对象反映此Class对象所表示的类或接口的指定已声明字段。

       注意:getField()和getDeclearedField()的区别在于前面这个方法值反映目标类中公共的成员变量,而后面这个方法反映的是目标类中已申明的成员变量。

    那么Field类中主要提供了哪些方法呢?

    1.Object get(Objectobj),该方法返回指定对象上此Field表示的字段的值。

              field.get(“目标类对象”);

       如何指向目标类中被private所修饰的成员变量呢?

    步骤一:要用Constructor类中的getDeclearedField()方法反映目标类中被private修饰的成员变量。

        Field field = 目标类对象.getClass().getDeclearedField(“成员变量名”);

    步骤二:然后调用Field父类AccessableObject类中的void setAccessable(boolean flag)方法设置目标类中的成员变量为可访问。

        field. setAccessable(true);

    步骤三:调用get()方法获取相应成员变量的值。

        field.get(“目标类对象”);

成员方法的反射-Method类

    Method类也是java.lang.reflect包中的一个类,它的实例对象代表类中的某一个成员方法。同理Field类不提供构造方法,要获取Method类的实例对象,同样首先要获取目标类的Class实例对象。

    1.MethodgetMethod(String name, Class<?>… parameterTypes),该方法返回一个Method实例对象,它反映此Class对象所表示的类或接口的指定公共成员方法。该成员方法是根据getMethod方法所接收到的参数来确定的。比如:

        //获取Method类实例对象,此对象反映了String类中参数为int类型的charAt()方法.

        Method reflectMethod= String.class.getMethod(“charAt”,int.class);

    2.Object invoke(Objectobj, Object…args),Method类中的方法,该方法激发Method类实例对象所反映的目标类中的成员方法,参数根据目标类中的成员方法传入,返回值类型也和其相同。

        char ch = reflectMethod.invoke(“目标类实例对象”, 1);

    注意:如果invoke()方法接收到的第一个参数是null,则表示Method实例对象对应的是一个静态方法,因为静态方法不需要对象调用,所以接收的参数就是null。

对接受数组参数的成员方法进行反射

    当目标类中的成员方法所接受的参数是一个数组时,调用invoke()方法激发该方法时,invoke()方法所接收的参数不能是一个数组类型。原因是按照java1.5的语法,整个参数是一个数组,而按照java1.4的语法,数组中的每个元素对应的是一个参数,由于java1.5要兼容java1.4的语法,所以虚拟机会按照java1.4的语法进行处理,即把数组拆开成为若干个单独的参数。所以,在反射参数为数组的成员方法时,不能使用代码:

        reflectMethod.invoke(“目标类对象名”, newint[]{“…”});

因为javac会把它当做1.4的语法进行处理,所以会出现参数个数不匹配的异常。那么要如何解决这样的问题呢?

    此时,可以将接收的数组参数进行装饰,用new Object[]{new int[]{“…”}}方式将参数修饰,或者将数组强制转换成为Object类型。如下:

        reflectMethod.invoke(“目标类对象”, newObject[]{new int[]{“…”}});  或者

        reflectMethod.invoke(“目标类对象”, (Object)newint[]{“…”});

此时,编译器编译时就不会把它当做数组看待,也就不会把数组再拆开成若干个参数了。

 

 

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值