当我们声明了一个泛型的接口或类,或需要一个子类继承至这个泛型类,而我们又希望利用反射获取这些泛型参数信息。这就是本文将要介绍的ReflectionUtil就是为了解决这类问题的辅助工具类,为java.lang.reflect标准库的工具类。它提供了便捷的访问泛型对象类型(java.reflect.Type)的反射方法。

本文假设你已经了解java反射知识,并能熟练的应用。如果还不了解java反射知识,那么你可以先移步到Oracel反射课程,这可能是你开始学习反射的好起点.

ReflectionUtil中包含以下几种功能:

  1. 通过Type获取对象class;
  2. 通过Type创建对象;
  3. 获取泛型对象的泛型化参数;
  4. 检查对象是否存在默认构造函数;
  5. 获取指定类型中的特定field类型;
  6. 获取指定类型中的特定method返回类型;
  7. 根据字符串标示获取枚举常量;
  8. ReflectionUtil下载地址.

通过Type获取对象class

private static final String TYPE_NAME_PREFIX = "class ";

public static String getClassName(Type type) {
if (type==null) {
return "";
}
String className = type.toString();
if (className.startsWith(TYPE_NAME_PREFIX)) {
className = className.substring(TYPE_NAME_PREFIX.length());
}
return className;
} public static Class<?> getClass(Type type)
throws ClassNotFoundException {
String className = getClassName(type);
if (className==null || className.isEmpty()) {
return null;
}
return Class.forName(className);
}

方法ReflectionUtil#getClass(Type)实现了从java.lang.reflect.Type获取java.lang.Class对象名称。这里利用了Type的toString方法获取所在类型的class。如“class some.package.Foo”,截取后部分class名称,在利用Class.forName(String)获取class对象。

通过Type创建对象

public static Object newInstance(Type type)
throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class<?> clazz = getClass(type);
if (clazz==null) {
return null;
}
return clazz.newInstance();
}

方法ReflectionUtil#newInstance(Type type)实现根据Type构造对象实例。在这里输入的Type不能是抽象类、接口、数组类型、以及基础类型、Void否则会发生InstantiationException异常。

获取泛型对象的泛型化参数

首先假设我们有如下两个对象:

public abstract class Foo<T> {
//content
} public class FooChild extends Foo<Bar> {
//content
}

怎么获取子类在Foo中传入的泛型Class类型呢?

比较常用的做法有以下两种:

强制FooChild传入自己的class类型(这也是比较常用的做法):

public abstract class Foo<T> {
private Class<T> tClass; public Foo(Class<T> tClass) {
this.tClass = tClass;
}
//content
} public class FooChild extends Foo<Bar> {
public FooChild() {
super(FooChild.class);
}
//content
}

利用反射获取:

public static Type[] getParameterizedTypes(Object object) {
Type superclassType = object.getClass().getGenericSuperclass();
if (!ParameterizedType.class.isAssignableFrom(superclassType.getClass())) {
return null;
}
return ((ParameterizedType)superclassType).getActualTypeArguments();
}

方法ReflectionUtil#getParameterizedTypes(Object)利用反射获取运行时泛型参数的类型,并数组的方式返回。本例中为返回一个T类型的Type数组。

为了Foo得到T的类型我们将会如下使用此方法:

...
Type[] parameterizedTypes = ReflectionUtil.getParameterizedTypes(this);
Class<T> clazz = (Class<T>)ReflectionUtil.getClass(parameterizedTypes[0]);
...

注意:

在java.lang.reflect.ParameterizedType#getActualTypeArguments() documentation:的文档中你能看见如下文字:

in some cases, the returned array can be empty. This can occur. if this type represents
a non-parameterized type nested within a parameterized type.

当传入的对象为非泛型类型,则会返回空数组形式。

检查对象是否存在默认构造函数

public static boolean hasDefaultConstructor(Class<?> clazz) throws SecurityException {
Class<?>[] empty = {};
try {
clazz.getConstructor(empty);
} catch (NoSuchMethodException e) {
return false;
}
return true;
}

方法ReflectionUtil#hasDefaultConstructor利用java.lang.reflect.Constructor检查是否存在默认的无参构造函数。

获取指定类型中的特定field类型

public static Class<?> getFieldClass(Class<?> clazz, String name) {

if (clazz==null || name==null || name.isEmpty()) {
return null;
}
name = name.toLowerCase();
Class<?> propertyClass = null;
for (Field field : clazz.getDeclaredFields()) {
field.setAccessible(true);
if (field.getName().equals(name)) {
propertyClass = field.getType();
break;
}
}
return propertyClass;

}

在某些情况下你希望利用已知的类型信息和特定的字段名字想获取字段的类型,那么ReflectionUtil#getFieldClass(Class<?>, String)可以帮助你。ReflectionUtil#getFieldClass(Class<?>, String) 利用Class#getDeclaredFields()获取字段并循环比较java.lang.reflect.Field#getName()字段名称,返回字段所对应的类型对象。

获取指定类型中的特定method返回类型

public static Class<?> getMethodReturnType(Class<?> clazz, String name) {
if (clazz==null || name==null || name.isEmpty()) {
return null;
} name = name.toLowerCase();
Class<?> returnType = null; for (Method method : clazz.getDeclaredMethods()) {
if (method.getName().equals(name)) {
returnType = method.getReturnType();
break;
}
} return returnType;
}

方法ReflectionUtil#getMethodReturnType(Class<?>, String)可以帮助你根据对象类型和方法名称获取其所对应的方法返回类型。ReflectionUtil#getMethodReturnType(Class<?>, String)利用Class#getDeclaredMethods()并以java.lang.reflect.Method#getName()比对方法名称,返回找到的方法的返回值类型(Method#getReturnType()).

根据字符串标示获取枚举常量

@SuppressWarnings({ "unchecked", "rawtypes" })
public static Object getEnumConstant(Class<?> clazz, String name) {
if (clazz==null || name==null || name.isEmpty()) {
return null;
}
return Enum.valueOf((Class<Enum>)clazz, name);
}

方法ReflectionUtil#getEnumConstant(Class<?>, String)为利用制定的枚举类型和枚举名称获取其对象。这里的名称必须和存在的枚举常量匹配。

ReflectionUtil下载地址

你可以从这里下载ReflectionUtil.java. 原英文版地址: http://qussay.com/2013/09/28/handling-java-generic-types-with-reflection/

(翻译)反射处理java泛型的更多相关文章

  1. java反射之java 泛型的本质

    1.泛型 反射API用来生成在当前JAVA虚拟机中的类.接口或者对象的信息.Class类:反射的核心类,可以获取类的属性,方法等内容信息.Field类:Java.lang.reflect.表示类的属性 ...

  2. Java泛型反射机制(二)

    /** * @author Administrator * 好处:泛型:1安全 2减少代码重用率 */ package com.test; import java.lang.reflect.Metho ...

  3. 已看1.熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的Java API,包括集合框架、多线程(并发编程)、I/O(NIO)、Socket、JDBC、XML、反射等。[泛型]\

    1.熟练的使用Java语言进行面向对象程序设计,有良好的编程习惯,熟悉常用的Java API,包括集合框架.多线程(并发编程).I/O(NIO).Socket.JDBC.XML.反射等.[泛型]\1* ...

  4. Java泛型和反射

    1. 字节码对象的三种获取方式 以String为例 Class<? extends String> strCls = "".getClass(); Class<S ...

  5. Java反射的理解(六)-- 通过反射了解集合泛型的本质

    Java反射的理解(六)-- 通过反射了解集合泛型的本质 上述写了那么多,我们可能会有个疑问,为什么要用反射,步骤比我们常规的加载类操作复杂多了,别急,这个问题我最后才解答,我们先来了解集合泛型的本质 ...

  6. java 反射和泛型-反射来获取泛型信息

    通过指定对应的Class对象,程序可以获得该类里面所有的Field,不管该Field使用private 方法public.获得Field对象后都可以使用getType()来获取其类型. Class&l ...

  7. java 编程基础 反射方式获取泛型的类型Fileld.getGenericType() 或Method.getGenericParameterTypes(); (ParameterizedType) ;getActualTypeArguments()

    引言 自从JDK5以后,Java Class类增加了泛型功能,从而允许使用泛型来限制Class类,例如,String.class的类型实际上是 Class 如果 Class 对应的类暂时未知,则使 C ...

  8. Java泛型深入理解(转载)

    原文地址  http://blog.csdn.net/sunxianghuang/article/details/51982979 泛型之前 在面向对象编程语言中,多态算是一种泛化机制.例如,你可以将 ...

  9. 深入理解什么是Java泛型?泛型怎么使用?【纯转】

    本篇文章给大家带来的内容是介绍深入理解什么是Java泛型?泛型怎么使用?有一定的参考价值,有需要的朋友可以参考一下,希望对你们有所助. 一.什么是泛型 “泛型” 意味着编写的代码可以被不同类型的对象所 ...

随机推荐

  1. 为什么不能访问django自带的索引页

    通过HTTP://192.168.160.128:8000访问虚拟机上的django索引页出现“ 无法访问此网站 192.168.160.128 拒绝了我们的连接请求. ” 是什么原因呢?费了好大一番 ...

  2. [php-src]扩展中封装业务与 call_user_function 的使用建议

    内容均以php5.6.14为例. 从一个封装 uniqid 的例子来讲. /* {{{ wrapper of uniqid */ PHP_FUNCTION(fox) { // #1. zval *pr ...

  3. select制作分层级目录,让select显示和可下拉选择的"不一样"

    今天遇到一个特殊的select问题,需求是这样的:每次点击这个select时,根据选择的option的值做出相应的处理并返回新的select,option内容.所以大致思路是给这个select绑定ch ...

  4. hasOwnProperty和in

    返回一个布尔值,指出一个对象是否具有指定名称的属性. hasOwnProperty 此方法无法检查该对象的原型链中是否具有该属in 可以检查原型链中是否具有该属

  5. 封装ios静态库碰到的一些问题(三)

    静态库封装好以后,就存在一个问题,静态库,模拟器的静态库何真机的静态库是分开的,那么能够合并,答案是肯定的,但是必须我们手工在终端工具下执行命令合并 lipo -create Release-ipho ...

  6. 【笔记】memorymanagement-whitepaper-150215

    3 GC概念 Gc的职责: 1)  分配内存 2)  保证被引用的对象驻留内存 3)  对象不可达后将其占用内存回收 被引用对象被称为 “存活对象”. 不再被引用的对象称为“垃圾对象”. 找到垃圾对象 ...

  7. PWM波控制舵机总结

    文章转自:http://www.geek-workshop.com/thread-70-1-1.html 一.关于舵机: 舵机(英文叫Servo):它由直流电机.减速齿轮组.传感器和控制电路组成的一套 ...

  8. Nessus导入Cookie进行Web应用安全扫描

    在不导入Cookie使用Nessus进行扫描的时候,扫描的结果是比较简单的,很多深层的问题无法被扫描出来. 需要我们手动导入Cookie,带着Cookie的状态扫描的结果会更详细更深入,以下是操作步骤 ...

  9. MyBatis SQL动态装配

    MyBatis的方便在于可以配置动态SQL,通过过滤器进行动态装配.在刚开始使用中,遇到不少问题,其中update语句也需要动态装配,核心在于DAO层要与.xml文件中的语句和变量名要匹配.例如: D ...

  10. 代码规范、GitHub提交源码的标准 答题人-杨宇杰

    1.格式与命名规范1.1 缩进 使用Tab缩进,而不是空格键1.2 换行 每行120字符 if,for,while语句只有单句时,如果该句可能引起阅读混淆,需要用" {"和&quo ...