java的反射(java.lang.Class 、java.lang.reflect )

学习参考  java 编程动态性文章:

反射基础

1、使用反射的启点总是 java.lang.Class 实例

如果您希望与预先定义的类协作,那么Java语言提供一种直接获得  Class  实例的简便快捷方式:
Class clas = MyClass.class;
当您使用这一项技术时,装入类涉及的所有工作在幕后进行。

但,如果您需要在运行时从某些外部源读取类名,这种方法并不适合。实际上,您需要使用一个类装载器来查找类信息。以下介绍一种方法:

try{
Class<?> class = Class.forName(name);//此方法会完成类的初始化工作(执行静态块)
}catch(ClassNotFoundException e){
   e.printStackTrace();
}
//如果已经装入了类,您将得到现有的 Class 信息。如果类未被装入,类装入器将现在装入并返回新创建的类实例。



2、得到Class 对象后,可以获得类自身的信息,如:包和父类、及实现的接口、定义的构造函数和属性、方法等信息。


用户查找构造函数的一组反射调用:
          
Constructor<T>getConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。

返回一个  Constructor 对象,它反映此  Class 对象所表示的类的指定公共构造方法。 parameterTypes 参数是  Class 对象的一个数组,这些 Class 对象按声明顺序标识构造方法的形参类型。
Constructor<?>[]getConstructors()
返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。

Constructor<T>getDeclaredConstructor(Class<?>... parameterTypes)
返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法

Constructor<?>[]getDeclaredConstructors()
返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。


这些调用都返回一个或多个  java.lang.reflect.Constructor  函数。这种  Constructor  类定义  ne wInstance  方法,它采用一组对象作为其唯一的参数,然后返回新创建的原始类实例。

3、得到构造函数后可以利用  java.lang.reflect.Constructor类 函数创建类的实例对象

java.lang.reflect.Constructor类 的 函数:

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

扩展:

java编程语言还定义了一种您可以用来使用 无参数(或缺省)构造函数创建类的一个实例的特殊快捷方式。这种快捷方式嵌入到 Class 定义中,如下:

Object newInstance() -- 使用缺省函数创建新的实例


4、获得Field  (类包含的属性)


  • Field getField(String name) -- 获得命名的公共字段
  • Field[] getFields() -- 获得类的所有公共字段
  • Field getDeclaredField(String name) -- 获得类声明的命名的字段
  • Field[] getDeclaredFields() -- 获得类声明的所有字段
a、然后调用java.lang.reflect.Field 类的方法 取得/设置某个对象该属性的值

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

voidset(Object obj, Object value)
将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
包含 getXXX  和  setXXX  方法。


b、获得属性上的注解
<T extends Annotation>
T
getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。

5、获得Method


  • Method getMethod(String name, Class[] params) -- 使用特定的参数类型,获得命名的公共方法

  •  Method[] getMethods() -- 获得类的所有公共方法
  •   Method getDeclaredMethod(String name, Class[] params) -- 使用特写的参    数类型,获得类声明的命名的方法
  • Method[] getDeclaredMethods() -- 获得类声明的所有方法
a、调用Method对象的invoke方法:
Objectinvoke(Object obj, Object... args)
对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。

这种  invoke  方法使用两个参数,为调用提供类实例和参数值数组。
  • 对带有指定参数的指定对象调用由此  Method 对象表示的底层方法。个别参数被自动解包,以便与基本形参相匹配,基本参数和引用参数都随需服从方法调用转换。

    如果底层方法是静态的,那么可以忽略指定的 obj 参数。该参数可以为 null。

    如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。

    如果底层方法是实例方法,则使用动态方法查找来调用它。

    案例:
        
     @Test
         public void testClassForname(){
               try {
                  Class<?> callClass = Class.forName("com.lucene.Student");
                  Method  method= callClass.getMethod("setName", new Class[]{String.class});
                  Method  method2= callClass.getDeclaredMethod( "getName", null );//得到无参的getName()方法
                  System. out.println(method.getName());
                  Object object = callClass.newInstance();
                   method.invoke(object, new String[]{"你好"});//调用object对象的指定方法,并传入 参数值(String数组)
                  System. out.println( method2.invoke(object, null));
              } catch (Exception e) {
                   // TODO Auto-generated catch block
                  e.printStackTrace();
              }
         }
    


反射数组

数组是Java编程语言中的对象。与所有对象一样,它们都有类。如果您有一个数组,使用标准 getClass 方法,您可以获得该数组的类,就象任何其它对象一样。但是,即使您有一个数组类,您也不能直接对它进行太多的操作 -- 反射为标准类提供的构造函数接入不能用于数组,而且数组没有任何可接入的字段,只有基本的 java.lang.Object 方法定义用于数组对象。

数组的特殊处理使用 java.lang.reflect.Array 类提供的静态方法的集合。该类中的方法使您能够创建新数组,获得数组对象的长度,读和写数组对象的索引值。

清单5显示了一种重新调整现有数组大小的有效方法。它使用反射来创建相同类型的新数组,然后在返回新数组之前,在老数组中复制所有数据。

清单 5:通过反射来扩展一个数组

public Object growArray(Object array, int size) {
    Class type = array.getClass().getComponentType();
    Object grown = Array.newInstance(type, size);
    System.arraycopy(array, 0, grown, 0,
        Math.min(Array.getLength(array), size));
    return grown;
}



Class 类的方法:
Class<?>getComponentType()
返回表示数组组件类型的 Class

Array类的静态方法:
staticObjectnewInstance(Class<?> componentType, int... dimensions)
创建一个具有指定的组件类型和维度的新数组。


安全性和反射

在处理反射时安全性是一个较复杂的问题。反射经常由框架型代码使用,由于这一点,您可能希望框架能够全面接入您的代码,无需考虑常规的接入限制。但是,在其它情况下,不受控制的接入会带来严重的安全性风险,如当代码在不值得信任的代码共享的环境中运行时。

由于这些互相矛盾的需求,Java编程语言定义一种多级别方法来处理反射的安全性。基本模式是对反射实施与应用于源代码接入相同的的限制:

  • 从任意位置到类公共组件的接入
  • 类自身外部无任何到私有组件的接入
  • 受保护和打包(缺省接入)组件的有限接入

不过-至少某些时候,围绕这些限制有一种简单的方法。我在前面实例中使用的 Constructor 、 Field 和 Method 类都扩展了一个普通的基本类--&#160 java.lang.reflect.AccessibleObject 类。该类定义一种 setAccessible 方法,使您能够启动或关闭对这些类中其中一个类的实例的接入检测。唯一的问题在于如果使用了安全性管理器,它将检测正在关闭接入检测的代码是否许可了这样做。如果未许可,安全性管理器抛出一个例外。

清单6展示了一个程序,在 清单 1TwoString 类的一个实例上使用反射来显示安全性正在运行:

清单 6:反射安全性正在运行

public class ReflectSecurity {
    public static void main(String[] args) {
        try {
            TwoString ts = new TwoString("a", "b");
            Field field = clas.getDeclaredField("m_s1");
//          field.setAccessible(true);
            System.out.println("Retrieved value is " +
                field.get(inst));
        } catch (Exception ex) {
            ex.printStackTrace(System.out);
        }
    }
}


如果您编译了这一程序,不使用任何特定参数直接从命令行运行,它将在 field.get(inst) 调用中抛出一个 IllegalAccessException 。如果您未注释 field.setAccessible(true) 代码行,那么重新编译并重新运行该代码,它将取得成功。最后,如果您在命令行添加了JVM参数 -Djava.security.manager 以实现安全性管理器,它将再次失败,除非您定义了 ReflectSecurity 类的许可权限。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值