前言

p.s: 本文需要读者对反射机制的API有一定程度的了解,如果之前没有接触过的话,建议先看一下官方文档的Quick Start。

在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的反射类Class,在Java中我们有三种方法可以获取一个对象的反射类。

通过getClass方法

在Java中,每一个Object都有一个getClass()方法,通过getClass方法我们可以获取到这个对象对应的反射类:

String s = "ziwenxie"; Class> c = s.getClass();

通过forName方法

我们也可以调用Class类的静态方法forName():

Class> c = Class.forName("java.lang.String");

使用.class

或者我们也可以直接使用.class:

Class> c = String.class;

获取类型信息

相信都知道反射的一大好处就是可以允许我们在运行期间获取对象的类型信息,下面我们通过一个例子来具体看一下。

首先我们在typeinfo.interfacea包下面新建一个接口A:

package typeinfo.interfacea; public interface A { void f(); }

接着我们在typeinfo.packageaccess包下面新建一个接口C,接口C继承自接口A,并且我们还另外创建了几个用于测试的方法,注意下面几个方法的权限都是不同的。

package typeinfo.packageaccess; import typeinfo.interfacea.A; class C implements A { public void f() { System.out.println("public C.f()"); } public void g() { System.out.println("public C.g()"); } protected void v () { System.out.println("protected C.v()"); } void u() { System.out.println("package C.u()"); } private void w() { System.out.println("private C.w()"); } } public class HiddenC { public static A makeA() { return new C(); } }

在callHiddenMethod()方法中我们用到了几个新的API,其中getDeclaredMethod()根据方法名用于获取Class类指代对象自己声明的某个方法,然后我们通过调用invoke()方法就可以触发对象的相关方法:

package typeinfo; import typeinfo.interfacea.A; import typeinfo.packageaccess.HiddenC; import java.lang.reflect.Method; public class HiddenImplementation { public static void main(String[] args) throws Exception { A a = HiddenC.makeA(); a.f(); System.out.println(a.getClass().getName()); // Oops! Reflection still allows us to call g(): callHiddenMethod(a, "g"); // And even methods that are less accessible! callHiddenMethod(a, "u"); callHiddenMethod(a, "v"); callHiddenMethod(a, "w"); } static void callHiddenMethod(Object a, String methodName) throws Exception { Method g = a.getClass().getDeclaredMethod(methodName); g.setAccessible(true); g.invoke(a); } }

从输出结果我们可以看出来,不管是public,default,protect还是pricate方法,通过反射类我们都可以自由调用。当然这里我们只是为了显示反射的强大威力,在实际开发中这种技巧还是不提倡。

public C.f() typeinfo.packageaccess.C public C.g() package C.u() protected C.v() private C.w()

上面我们只是测试了Method对象,感兴趣的读者在熟悉了反射的API之后,不妨测试一下Filed,这里我们就不重复了。

与注解相结合

在单元测试框架比如Junit中反射机制也得到了广泛的应用,即通过注解的方式。下面我们简单地来了解一下如何通过反射机制来获取相关方法的注解信息,比如说我们有下面这样一个业务场景,当用户在修改自己密码的时候,为了保证密码的安全性,我们要求用户的新密码要满足一些条件,比如说至少要包含一个非数字字符,不能与以前的密码相同之类的条件等。

import java.lang.annotation.* @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface UserCase { public int id(); public String description() default "no description"; }

下面是我们检测密码的工具类的实现:

public class PasswordUtils { @UserCase(id=47, description="Password must contain at least one numeric") public boolean validatePassword(String password) { return (password.matches("\\w*\\d\\w*")); } @UserCase(id=48) public String encryptPassword(String password) { return new StringBuilder(password).reverse().toString(); } @UserCase(id=49, description="New passwords can't equal previously used ones") public boolean checkForNewPassword(List prevPasswords, String password) { return !prevPasswords.contains(password); } }

利用反射我们可以写出更加清晰的测试代码,其中getDeclaredMethods()方法可以获取相关对象自己声明的相关方法,而getAnnotation()则可以获取Method对象的指定注解。

public class UseCaseTracker { public static void trackUseCases(List useCases, Class> cl) { for(Method m : cl.getDeclaredMethods()) { UseCase uc = m.getAnnotation(UseCase.class); if(uc != null) { System.out.println("Found Use Case: " + uc.id() + " " + uc.description()); useCases.remove(new Integer(uc.id())); } } for(int i : useCases) { System.out.println("Warning: Missing use case-" + i); } } public static void main(String[] args) { List useCases = new ArrayList(); Collections.addAll(useCases, 47, 48, 49, 50); trackUseCases(userCases, PasswordUtils.class); } }

解决泛型擦除

现在有下面这样一个业务场景,我们有一个泛型集合类List

public class Pet extends Individual { public Pet(String name) { super(name); } public Pet() { super(); } } public class Cat extends Pet { public Cat(String name) { super(name); } public Cat() { super(); } } public class Dog extends Pet { public Dog(String name) { super(name); } public Dog() { super(); } } public class EgyptianMau extends Cat { public EgyptianMau(String name) { super(name); } public EgyptianMau() { super(); } } public class Mutt extends Dog { public Mutt(String name) { super(name); } public Mutt() { super(); } }

上面的Pet类继承自Individual,Individual类的的实现稍微复杂一点,我们实现了Comparable接口,重新自定义了类的比较规则,如果不是很明白的话,也没有关系,我们已经将它抽象出来了,所以不理解实现原理也没有关系。

public class Individual implements Comparable { private static long counter = 0; private final long id = counter++; private String name; // name is optional public Individual(String name) { this.name = name; } public Individual() {} public String toString() { return getClass().getSimpleName() + (name == null ? "" : " " + name); } public long id() { return id; } public boolean equals(Object o) { return o instanceof Individual && id == ((Individual)o).id; } public int hashCode() { int result = 17; if (name != null) { result = 37 * result + name.hashCode(); } result = 37 * result + (int) id; return result; } public int compareTo(Individual arg) { // Compare by class name first: String first = getClass().getSimpleName(); String argFirst = arg.getClass().getSimpleName(); int firstCompare = first.compareTo(argFirst); if (firstCompare != 0) { return firstCompare; } if (name != null && arg.name != null) { int secendCompare = name.compareTo(arg.name); if (secendCompare != 0) { return secendCompare; } } return (arg.id < id ? -1 : (arg.id == id ? 0 : 1)); } }

下面创建了一个抽象类PetCreator,以后我们通过调用arrayList()方法便可以直接获取相关Pet类的集合。这里使用到了我们上面没有提及的newInstance()方法,它会返回Class类所真正指代的类的实例,这是什么意思呢?比如说声明new Dog().getClass().newInstance()和直接new Dog()是等价的。

public abstract class PetCreator { private Random rand = new Random(47); // The List of the different getTypes of Pet to create: public abstract List> getTypes(); public Pet randomPet() { // Create one random Pet int n = rand.nextInt(getTypes().size()); try { return getTypes().get(n).newInstance(); } catch (InstantiationException e) { throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } public Pet[] createArray(int size) { Pet[] result = new Pet[size]; for (int i = 0; i < size; i++) { result[i] = randomPet(); } return result; } public ArrayList arrayList(int size) { ArrayList result = new ArrayList(); Collections.addAll(result, createArray(size)); return result; } }

接下来我们来实现上面这一个抽象类,解释一下下面的代码,在下面的代码中,我们声明了两个集合类,allTypes和types,其中allTypes中包含了我们呢上面所声明的所有类,但是我们具体的类型实际上只有两种即Mutt和EgypianMau,所以我们真正需要new出来的宠物只是types中所包含的类型,以后我们通过调用getTypes()便可以得到types中所包含的所有类型。

public class LiteralPetCreator extends PetCreator { @SuppressWarnings("unchecked") public static final List> allTypes = Collections.unmodifiableList( Arrays.asList(Pet.class, Dog.class, Cat.class, Mutt.class, EgyptianMau.class)); private static final List> types = allTypes.subList( allTypes.indexOf(Mutt.class), allTypes.size()); public List> getTypes() { return types; } }

总体的逻辑已经完成了,最后我们实现用来统计集合中相关Pet类个数的TypeCounter类。解释一下isAssignalbeFrom()方法,它可以判断一个反射类是某个反射类的子类或者间接子类。而getSuperclass()顾名思义就是得到某个反射类的父类了。

public class TypeCounter extends HashMap, Integer> { private Class> baseType; public TypeCounter(Class> baseType) { this.baseType = baseType; } public void count(Object obj) { Class> type = obj.getClass(); if (!baseType.isAssignableFrom(type)) { throw new RuntimeException( obj + " incorrect type " + type + ", should be type or subtype of " + baseType); } countClass(type); } private void countClass(Class> type) { Integer quantity = get(type); put(type, quantity == null ? 1 : quantity + 1); Class> superClass = type.getSuperclass(); if (superClass != null && baseType.isAssignableFrom(superClass)) { countClass(superClass); } } @Override public String toString() { StringBuilder result = new StringBuilder("{"); for (Map.Entry, Integer> pair : entrySet()) { result.append(pair.getKey().getSimpleName()); result.append("="); result.append(pair.getValue()); result.append(", "); } result.delete(result.length() - 2, result.length()); result.append("} "); return result.toString(); } }

参考文献

THINKING IN JAVA

java反射机制的实现机制_Java反射机制实践相关推荐

  1. java反射什么时候用到_Java 反射最佳实践

    概要:最简单优雅的使用反射. 本文的例子都可以在示例代码中看到并下载,如果喜欢请star,如果觉得有纰漏请提交issue,如果你有更好的点子可以提交pull request.本文的示例代码主要是基于 ...

  2. java反射机制原理详解_java反射机制的详细讲解

    一 , 什么是java反射机制? JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象 ...

  3. java反射机制深入详解_Java反射机制深入详解

    原标题:Java反射机制深入详解 一.概念 反射就是把Java的各种成分映射成相应的Java类. Class类的构造方法是private,由JVM创建. 反射是java语言的一个特性,它允程序在运行时 ...

  4. java反射进行字段类型判断_Java反射机制的讲解

    Java中的反射提供了一种运行期获取对象元信息的手段.即正常方法是通过一个类创建对象,反射方法就是通过一个对象找到一个类的信息. Java的反射机制的实现要借助于4个类:class,Construct ...

  5. java反射可以获得什么属性_java反射获得属性的值

    java反射api_IT/计算机_专业资料.java反射教程,深刻理解java反射,反射 聯絡郵箱:zhiyong.tong@ 反射 API 反射 API 表現,或者反射類,接口,和對象在現..... ...

  6. java測試動態方法_java反射学习

    反射的核心Class类 Class类是一个特殊的类,不能手动创建,只能由jvm来创建. jvm在类加载时会为每个类生成一个与之对应的Class对象在Java堆中(且每个类只会有一个对应的Class对象 ...

  7. java根据field名获取变量_Java反射有多强?这5大神奇功能,你需要了解!

    点击上方"蓝字",关注了解更多 什么是反射? 在Java中,对于任意一个运行中的对象,可以调用该对象的任意属性和方法:已知一个类,可以获取这个类的所有属性和方法,这就是反射机制. ...

  8. java 反射获取父类的字段_java反射获取父类和子类字段值、赋值

    这里将告诉您java反射获取父类和子类字段值.赋值,具体操作过程:java反射获取字段值.赋值 import org.springframework.util.ReflectionUtils; imp ...

  9. Java动物类enjoy方法打印_Java反射学习-2 - 获取Class对象的三种方式

    1 packagecn.tx.reflect;2 3 importjava.lang.reflect.Constructor;4 importjava.lang.reflect.Field;5 imp ...

  10. java中不用impore导入的_java import机制(不用IDE)

    java包有两种导入机制 单类型导入 import java.lang.Object; 这个比较好理解 2. 按需类型导入 import java.lang.*; 这个不是把lang下面的所有的类都导 ...

最新文章

  1. python文本数据转换数值矩阵_python numpy矩阵的数据类型转换
  2. Spring的静态代理和动态代理
  3. 组件命名方式||局部组件注册:局部组件只能在注册他的父组件中使用
  4. mysql datatable_MySQL-数据表操作
  5. 奇迹觉醒服务器找不到,奇迹MU觉醒与服务器断开连接 原因及解决办法
  6. 这短短几行代码价值一万
  7. RecyclerView的使用和样式
  8. Vue框架里使用Swiper - 安装篇
  9. 构件与构架,我的理解
  10. 【实用工具】之CSDN表格模板
  11. Android控件Gallery 3D效果
  12. SQL Server 2008数据备份与还原
  13. 金额转换,阿拉伯数字转换成中国传统形式
  14. 安卓手机怎么下载java游戏
  15. 在线协助设计软件,figma、sketch、xd哪个才是你的优先选择
  16. 【AI测试】人工智能测试整体介绍——第四部分
  17. python按时间截取视频,python使用opencv按一定间隔截取视频帧
  18. ThinkPHP校园后勤在线报修系统
  19. 台达服务器显示ale02,台达伺服电机50问2012.pdf
  20. 路由器篇-极路由1S(智能无线路由器)配置

热门文章

  1. 算法面试题_求给定字符串的排列、组合、八皇后问题
  2. python_四元数q转旋转矩阵R(已验证)
  3. 如何保存浮点型数值的图像? (Python的/ PIL)
  4. 深度学习优化方法总结比较(SGD,Adagrad,Adadelta,Adam,Adamax,Nadam)
  5. 2.WebDriver-元素定位 -(一)
  6. vue: 从组件通讯到vuex (上)
  7. 简单聊一下const
  8. 1414 冰雕(思维+暴力)
  9. C#的变迁史 - C# 5.0 之其他增强篇
  10. 看书看困了,写几句提提精神