增强反射 — Mirror

Jul 10, 2017 10:38:44 AM

作者:zozoh

反射的意义

Java 是静态语言。但是 JVM 却不那么静态。静态语言的好处是,IDE 可以提供很高级的重构功能。缺点是你的代码会比较僵化,像 Javascript 一样的动态语言(或者说,后绑定语言),在编写程序时的随心所欲,估计 Java 程序员是享受不到了。 但是好在 Java 还提供了“反射”。

在任何时候,你如果想在运行时决定采用哪个实现类,或者调用哪个方法,通过反射都可以实现,虽然不那么方便 (你需要捕捉很多无聊的异常),虽然不那么快。

既然这样,那么能不能让反射工作的更好一些呢?org.nutz.langGit@OSC镜像 包提供了Mirror<T> 类,通过它,你可以更方便的使用反射的特性

创建 Mirror

Mirror 就是 Class 的一个包裹:

  1. Mirror<Pet> mirror = Mirror.me(Pet.class);

更多时候,Mirror 用不到类型:

  1. Mirror<?> mirror = Mirror.me(Pet.class);

一旦你获得了 Mirror 对象,你就可以做如下操作:

更方便的构造

反射的 Class.newInstance() 是个很方便的函数。但是它只能调用默认构造函数。如果你想调用类的某个带参数的构造函数,是很麻烦的。通过 Mirror 你可以

自动判断构造函数

比如类:

  1. public class Pet{
  2. private String name;
  3. public Pet(String name){
  4. this.name = name;
  5. }
  6. }

通过如下调用:

  1. Mirror.me(Pet.class).born("XiaoBai");

Mirror 会自动根据你的参数寻找到相应的构造函数的。

自动判断工厂方法

比如类:

  1. public class Pet{
  2. private String name;
  3. public static Pet create(String name){
  4. return new Pet("Pet:" + name);
  5. }
  6. private Pet(String name){
  7. this.name = name;
  8. }
  9. }

通过如下调用:

  1. Mirror.me(Pet.class).born("XiaoBai");

Mirror 会自动根据你的参数寻找到相应的工厂方法。

构造函数最优先,如果找不到构造函数会寻找静态工厂方法

自动转换类型

  1. public class Pet{
  2. private String name;
  3. private Calendar birthday;
  4. private Pet(String name,Calendar birthday){
  5. this.name = name;
  6. this.birthday = birthday;
  7. }
  8. }

通过如下调用:

  1. Mirror.me(Pet.class).born("XiaoBai", "2008-10-12 12:23:24");

Mirror 会尝试寻找接受两个字符串的构造函数。如果找不到,它发现构造函数 Pet(String, Calendar) 起码参数的数量是一致的,于是就尝试通过 Castors 将 "2008-10-12 12:23:24" 转换成一个 Calendar

更快的构建 - 缓存构造方法

就像你知道的一样, Mirror 根据参数自动判断一个类型的构造函数,过程比较费时。一旦它找到了一个构造函数,或者一个静态工厂方法,我们就希望把它记下来,所以你可以:

  1. Mirror<Pet> mirror = Mirror.me(Pet.class);
  2. Borning<Pet> borning = mirror.getBorning("XiaoBai");
  3. Pet xb = borning.born("XiaoBai");
  4. Pet xh = borning.born("XiaoHei");

更方便的调用

Java 的反射允许你在运行时决定调用一个类的某一个成员方法。 通过 Mirror 调用的过程将会变得更加简单。

调用一个函数

比如你有一个类:

  1. public class MyClass {
  2. public String getInfo(String s) {
  3. return "Get " + s + " @ " + System.currentTimeMillis();
  4. }
  5. }

你可以这么调用 getInfo 方法:

  1. Mirror<MyClass> mirror = Mirror.me(MyClass.class);
  2. MyClass mc = mirror.born();
  3. System.out.println(mirror.invoke(mc, "getInfo", "Hello~~~"));

控制台输出:

  1. Get Hello~~~ @ 1259836169165

参数自动转型

  1. System.out.println(mirror.invoke(mc, "getInfo", new Email("zozoh", "263.net")));

控制台输出:

  1. Get zozoh@263.net @ 1259836289830

当然, Email 类的 toString() 需要正常工作。 实际上,它是利用 Castors 来做对象的转型的。

更方便的获取和设置

获取泛型参数

  • 如果没有泛型参数,返回 null
  1. Type[] types = Mirror.getTypeParams(MyClass.class);

获取 getter

  1. // 获取 getName() 方法
  2. Method getter = mirror.getGetter("name");

获取 setter

  1. // 获取 setName(String) 方法
  2. Method setter = mirror.getSetter("name", String.class);

获取全部属性

获得所有的属性,包括私有属性。不包括 Object 的属性

  1. Field[] fields = mirror.getFields();

获取全部方法

获取所有的方法,包括私有方法。不包括 Object 的方法

  1. Method[] methods = mirror.getMethods();

获取全部静态方法

  1. Method[] methods = mirror.getStaticMethods();

获取字段

  • 获取一个字段。这个字段可以是当前类型或者其父类的私有字段。
  1. Field f = mirror.getField("name");
  • 获取一组声明了特殊注解的字段
  1. Field[] fields = mirror.getFields(MyAnnotation.class);
  • 获取第一个声明了特殊注解的字段
  1. Field f = mirror.getField(MyAnnotation.class);

获取字段值

  • 不调用 getter,直接获得字段的值
  1. Object v = mirror.getValue(obj, mirror.getField("name"));
  • 优先通过 getter 获取字段值,如果没有,则直接获取字段值
  1. Object v = mirror.getValue(obj, "name");

设置字段值

  • 为对象的一个字段设值。 不会调用对象的 setter,直接设置字段的值
  1. mirror.setValue(obj, mirror.getField("name"), "XiaoBai");
  • 为对象的一个字段设置。优先调用 setter 方法。
  1. mirror.setValue(obj, "name", "XiaoBai");

获取静态字段

  • 取静态属性
  1. Field[] fields = mirror.getStaticField(nofinalOrAll);

本页面的文字允许在知识共享 署名-相同方式共享 3.0协议GNU自由文档许可证下修改和再使用。

原文: http://nutzam.com/core/lang/mirror.html