反射机制

反射机制

什么是反射机制

程序在运行时能够获取自身信息。(比如在java中,只要给定类的名字,就可以通过反射机制获取类的所有属性和方法)。

反射机制的作用

  • 在运行时判断任意一个对象所属的类
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时任意调用一个对象的方法
  • 在运行时构造任意一个类的对象

主要用于构造工具,而不是应用程序开发。

Class类

​ 在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。

这个信息跟踪着每个对象所属的类。可以通过Class类访问这些信息。

获取Class实例

三种方法:

  • Object getClass()
  • Class.forName()
  • T.class
   /**
     * 通过Object类中的getClass()
     * @return Class对象
     */
    private Class getClassInsatanceWayOne(){
        Person p = new Person();
        return p.getClass();
    }

    /**
     * 通过Class的静态方法forName
     * @return Class对象
     * @throws ClassNotFoundException
     */
    private Class getClassInstanceWayTwo() throws ClassNotFoundException {
        return Class.forName("reflect.Person");
    }

    /**
     * 通过T.class获取(T是任意Java类型)
     * @return Class对象
     */
    private Class getClassInstanceWayThree(){
        return Person.class;
    }

**注意:**一个Class对象实际上表示的是一个类型,而非一定是类。如int不是类,int.class是一个Class类型的对象。

Class实例的常见用法
getName
    /**
     * 通过Class实例获取类的名字
     * @param clazz
     * @return 类名
     */
    private String getClassName(Class clazz){
        return clazz.getName();
    }
==
/**
     * 比较两个类对象
     * @param clazz
     * @return true or false
     */
    private boolean isPersonClass(Class clazz){
        return clazz == Person.class;
    }
newInstance
    /**
     * 通过Class的newInstance创建对象(调用无参数构造,若要通过有参构造创建使用Constructor的newInstance)
     * @param clazz
     * @return object
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    private <T> T newInstance(Class clazz) throws IllegalAccessException, InstantiationException{
        return (T) clazz.newInstance();
    }
利用反射分析类的能力

检查类的结构

​ java.lang.reflect包下的FieldMethodConstructor分别描述了类的域、方法和构造器。可以使用 Modifier 类中的 isPublicisPrivateisFinal 判断方法或构造器是否是publicprivatefinal

​ Class类中的 getFieldsgetMethodsgetConstructors 方 法 将 分 别 返 回 类 提 供 的 public 域、 方法和构造器数组, 其中包括超类的公有成员。

​ Class 类的 getDeclareFieldsgetDeclareMethodsgetDeclaredConstructors 方法将分别返回类中声明的全部域、 方法和构 造器, 其中包括私有和受保护成员,但不包括超类的成员。

在运行时使用反射分析对象
   /**
    * 在运行时使用反射分析对象
    * @throws NoSuchFieldException
    * @throws IllegalAccessException
    */
   private void runtimeInstance() throws NoSuchFieldException, IllegalAccessException {
       Person p = new Person("BB","88");
       Class c1 = p.getClass();
       Field f = c1.getDeclaredField("name");
       //设置可以访问私有域
       f.setAccessible(true);
       //获取name属性的值
       Object v = f.get(p);
       System.out.println(v);
       //设置name属性的值
       f.set(p,"CC");
       System.out.println(f.get(p));
   }
使用反射编写泛型数组代码

将一个 Person[ ]临时地转换成 Object[ ] 数组, 然后 再把它转换回来是可以的,但一 从开始就是 Objectt[] 的数组却永远不能转换成 Person[]数组。

    /**
     * 扩充已填满的数组(运行时抛出类型转换错误)
     * @param a
     * @param newLength
     * @return
     */
    public static Object[] badCopy(Object[] a,int newLength){
        Object[] newArray = new Object[newLength];
        System.arraycopy(a,0,newLength,0,Math.min(a.length,newLength));
        return newArray;
    }

    /**
     * 通过反射,结合反射包下的Array来实现已满数组的扩容为可行方案
     * @param a
     * @param newLength
     * @return
     */
    public static Object goodCopyOf(Object a,int newLength){
        Class c1 = a.getClass();
        if(!c1.isArray()){
            return null;
        }
        Class componentType = c1.getComponentType();
        int length = Array.getLength(a);
        Object newArray = Array.newInstance(componentType,newLength);
        System.arraycopy(a,0,newArray,0,Math.min(length,newLength));
        return newArray;
    }
调用任意方法

在 Method 类中有一个 invoke 方法, 它允许调用包装在当前 Method 对象中 的方法 。

    public static void main(String[] args) throws Exception{
        Method sqrt = Math.class.getMethod("sqrt",double.class);
        printTable(1,10,10,sqrt);
    }
    
    public static void printTable(double from,double to,int n,Method f){
        System.out.println(f);
        double dx = (to-from)/(n-1);

        for(double x = from;x<=to;x+=dx){
            try {
                double y = (Double) f.invoke(null,x);
                System.out.printf("%10.4f | %10.4f%n",x,y);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }

参考

  • [1]《Java核心技术卷I》
  • [2] Hollis’s Blog
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值