Java反射机制应用实践
引言
Java反射机制是一个非常强大的功能,在很多大型项目比如Spring, Mybatis都可以看见反射的身影。通过反射机制我们可以在运行期间获取对象的类型信息,利用这一特性我们可以实现工厂模式和代理模式等设计模式,同时也可以解决Java泛型擦除等令人苦恼的问题。本文我们就从实际应用的角度出发,来应用一下Java的反射机制。
反射基础
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()
应用实践
我们有下面这样一个业务场景,我们有一个泛型集合类List<Class<? extends Pet>>
,我们需要统计出这个集合类中每种具体的Pet
有多少个。由于Java的泛型擦除,注意类似List<? extends Pet>
的做法肯定是不行的,因为编译器做了静态类型检查之后,到了运行期间JVM会将集合中的对象都视为Pet
,但是并不会知道Pet
代表的究竟是Cat
还是Dog
,所以到了运行期间对象的类型信息其实全部丢失了。p.s: 关于泛型擦除:我在上一篇文章里面有详细解释,感兴趣的朋友可以看一看。
为了实现我们上面的例子,我们先来定义几个类:
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<Individual> {private static long counter = 0;private final long id = counter++;private String name; // name is optionalpublic 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<Class<? extends Pet>> getTypes();public Pet randomPet() {// Create one random Petint 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<Pet> arrayList(int size) {ArrayList<Pet> result = new ArrayList<Pet>();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<Class<? extends Pet>> allTypes = Collections.unmodifiableList(Arrays.asList(Pet.class, Dog.class, Cat.class, Mutt.class, EgyptianMau.class));private static final List<Class<? extends Pet>> types = allTypes.subList(allTypes.indexOf(Mutt.class), allTypes.size());public List<Class<? extends Pet>> getTypes() {return types;}
}
总体的逻辑已经完成了,最后我们实现用来统计集合中相关Pet
类个数的TypeCounter
类。解释一下isAssignalbeFrom()
方法,它可以判断一个反射类是某个反射类的子类或者间接子类。而getSuperclass()
顾名思义就是得到某个反射类的父类了。
public class TypeCounter extends HashMap<Class<?>, 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);}}@Overridepublic String toString() {StringBuilder result = new StringBuilder("{");for (Map.Entry<Class<?>, 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();}
}
from: http://developer.51cto.com/art/201703/535488.htm
Java反射机制应用实践相关推荐
- 反射 字段_详解面试中常考的 Java 反射机制
反射(Reflection) 是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序对自身进行检查,或者说"自审",并能直接操作程序的内部属性和方法. 反射是一项高级 ...
- 初识java反射机制
这篇小博客有这么些内容~认识何使用java反射机制的心路历程 什么是java反射机制呢?什么时候会用到java反射机制呢?怎么使用java反射机制呢? 那我们开始吧~ (一)反射机制(Reflecti ...
- (转)个例子让你了解Java反射机制
个例子让你了解Java反射机制 原文地址:http://blog.csdn.net/ljphhj/article/details/12858767 JAVA反射机制: 通俗地说,反射机制就是可以把 ...
- 一个例子让你了解Java反射机制
本文来自:blog.csdn.net/ljphhj JAVA反射机制: 通俗地说,反射机制就是可以把一个类,类的成员(函数,属性),当成一个对象来操作,希望读者能理解,也就是说,类,类的成员,我们在运 ...
- java反射机制原理详解_java反射机制的详细讲解
一 , 什么是java反射机制? JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象 ...
- java反射机制_java反射机制的讲解
一 , 什么是java反射机制? JAVA反射机制是在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:这种动态获取信息以及动态调用对象 ...
- 一文带你了解Java反射机制
想要获取更多文章可以访问我的博客 - 代码无止境. 上周上班的时候解决一个需求,需要将一批数据导出到Excel.本来公司的中间件组已经封装好了使用POI生成Excel的工具方法,但是无奈产品的需求里面 ...
- 【面试】Java 反射机制(常见面试题)
文章目录 前言 一.反射是什么? 二.为什么要有反射 三.反射 API 3.1 获取 Class 对象的三种方式 3.2 获取成员变量 3.3 获取构造方法 3.4.获取非构造方法 四.实践 五.常见 ...
- 利用java反射机制 读取配置文件 实现动态类载入以及动态类型转换
作者:54dabang 在spring的学习过程之中,我们能够看出通过配置文件来动态管理bean对象的优点(松耦合 能够让零散部分组成一个总体,而这些总体并不在意之间彼此的细节,从而达到了真正的物理上 ...
最新文章
- wrs-tuya-cloud
- 控制iptables的nat转发端口的实现
- Opencv4.5.0+VS2019+win10环境配置
- 行为模式之Visitor模式
- Ambari 架构(三)Ambari Server 架构
- 从比特币脚本引擎到以太坊虚拟机
- python字符串替换功能string.replace()可以用正则表达式,更优雅
- android自定义控件实例
- ie compatibility
- 手游产品经理初探(三)产品中的玩家行为
- Dubbo zookeeper 初探【转】
- python开发软件有哪些?Python编程软件
- 【Java获取国家法定节假日三种工具类其三】
- autojs打开微信扫一扫,扫描二维码等信息的脚本
- 用NDK交叉编译pixman-0.34
- 网络安全之交换技术篇
- PCIe扫盲——PCIe错误源详解(一)
- “失败”的北漂十年,我真的尽力了。。。
- fpga的jtag接口扫不到器件_FPGA中AS和JTAG接口的使用
- spring事务@Transactional(readOnly = true)及隔离级别实验
热门文章
- 快速开发mina(翻译)
- 【项目实战】P2P金融数据指标分析
- 百度计算广告学沙龙学习笔记 - 内容匹配广告
- 算法与数据结构(希尔排序)
- Java 8 - 04 类型检查、类型推断以及限制
- 实战SSM_O2O商铺_42【前端展示】店铺列表页面View层的实现
- JVM-07垃圾收集Garbage Collection【GC日志分析】
- 全局事件-广播(Broadcast)
- python入门之控制结构顺序与选择结构_Python 入门之控制结构 - 顺序与选择结构——第1关:顺序结构...
- python创建列表_python创建与遍历List二维列表的方法