Java反射和注解

 www.lehu88.com     |      2019-08-13 23:46
Java反射和注解
https://docs.oracle.com/javase/tutorial/reflect/index.html
 
Java Reflection 反射机制:Java可以 获取/调用 任意已加载类的所有信息(字段/方法/构造函数)。甚至改变类中成员的各种属性(又如private改成public)。官方API说明都在 java.lang.reflect 。
 
假设目前我们只有奥迪车需要测试运行速度。
 
package com.car.test;
// Car.java
class Car {int velocity;}
// Runnable.java
interface Runnable {public void run();}
// Audi.java
public class Audi extends Car implements Runnable {
    Audi(int velocity){this.velocity = velocity;}
    public void run() {
      String className = this.getClass().getSimpleName();
      System.out.println(className + " run " + velocity + "km/h");
    }
}
// CarFactory.java
public class CarFactory {
    public static void main(String[] args) {
      Audi audi = new Audi(120);
      audi.run();
    }
}
上面因为我们知道需要测试的只有 Audi 这一种车型,所以在main里面可以直接用调用对应的构造函数进行测试,但是当我们的车型增加时(特斯拉也来啦),我们就不得不再次修改main函数。
 
public class CarFactory {
  public static void main(String[] args) {        
    Tesla tesla = new tesla(150);
    tesla.run();
  }
}
为了更好的测试不断新加车型,同时不修改我们的工厂测试主函数。我们可以:
 
package com.car.test;
// Tesla.java
// 省略以前已有不变的Audi
public class Tesla extends Car implements Runnable {
  Tesla(int velocity){this.velocity = velocity;}
  public void run() {
    String name = this.getClass().getSimpleName();
    System.out.println(name + " run " + velocity + "km/h");
  }
}
package com.car.test;
// CarFactory.java
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
 
public class CarFactory {
  public static void main(String[] args) {
    try {
      //通过命令行把动态所需要测试的类名传入测试主函数。
      //args[0] = "com.car.test.Tesla".
      //args[1] = "140".
      //得到类名.此函数需catch异常 ClassNotFoundException.
      Class<?> c = Class.forName(args[0]);            
      //找到对应的构造函数并构造出实例
      int velocity = Integer.parseInt(args[1]);
      Object car = c.getDeclaredConstructor(int.class).newInstance(velocity);
      //找到需要测试的函数定义 
      Method method = c.getDeclaredMethod("run");
      //执行对应函数
      method.invoke(car);
    } catch (ClassNotFoundException e) {
       e.printStackTrace();
    } catch (NoSuchMethodException e) {
       e.printStackTrace();
    } catch (IllegalAccessException e) {
       e.printStackTrace();
    } catch (InstantiationException e) {
       e.printStackTrace();
    } catch (InvocationTargetException e) {
       e.printStackTrace();
    }
 }
}
这样只要我们在命令行传入对应的类名,就可以执行对应的测试函数啦。
 
完美做到新加车型,不需要修改主测试函数。这就是java反射机制在运行时的一个基本示例。但是对于一个静态语言来说,这种动态调用太过灵活,所以需要每一步都要小心(上面的每个函数都需要catch异常)
 
With great power comes great responsibility.
 
上面就是事先不知道我们需要测试的是什么类,只有到了运行时才能得到对应的类,这就是应用反射机制的常用场景。它在运用在真实场景中一个典型例子就是 Junit ,它过去枚举了类中所有的方法 getDeclaredMethods() ,并把以 testXXX 开头的方法假设为测试函数并执行它们。但在 JUit4 后使用了注解(annotations)来替换了它。
 
不过注解的本质也是通过反射来实现的。
标签:www.lehu88.c

上一篇:PHP反序列化漏洞简介及相关技巧小结
下一篇:旷视5号员工陈可卿:1991生于绍兴、10岁买电脑改变命运,信息奥赛金牌保送清华