引言

自从JDK5以后,Java Class类增加了泛型功能,从而允许使用泛型来限制Class类,例如,String.class的类型实际上是 Class 如果 Class 对应的类暂时未知,则使 Class<?>。通过在反射中使用泛型,可以避免使用反射生成的对象需要强制类型转换。
泛型作用对比:
如下示例没有使用泛型时,编译不报错,运行时报错强制转换异常
public class HasNoFanxin {
public static Object newInstance(String className) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
Class clz = Class.forName(className);
return clz.newInstance();
}
public static void main(String[] args) throws InstantiationException, IllegalAccessException, ClassNotFoundException {
String str = (String) newInstance("java.lang.Date");
System.out.println(str);
}
}

如下使用泛型,输入有误的话编译时就会报异常,提前提示错误(编译时就自动推断了泛型的真实类型)

public class HasFanxin {
public static <T> T newInstance(Class<T> clz) throws InstantiationException, IllegalAccessException {
return clz.newInstance();
} public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Date str = newInstance(Date.class); // 这里传入什么类型,传出就必须是什么类型,如果写成了String str = ... 就会编译报错
}
}

通过反射获取变量、方法形参的泛型类型

以获取类变量泛型为例

前提:
通过反射获取类对应的成员变量Field
获取步骤:
1. 获得成员变量的类型
  • Type gType = f.getGenericType();
2. 判断类型是否为带泛型的类型
  • gtype instanceof ParameterizedType
3. 将判断为待泛型的Type对象强制转换为ParameterizedType对象,(ParameterizedType代表被参数化的类型:也就是增加了泛型限制的类型)
  • ParameterizedType ptype = (ParameterizedType) type
4.通过强制转换后的ParameterizedType带泛型对象获取泛型的类型

getRawType() 返回没有泛型信息的原始类型。

getActualTypeArguments(): 返回泛型参数的类型Type 数组。

  • Type[] types = ptype.getActualTypeArguments();

获取方法参数的泛型,可以通过反射方法的参数本身Parameter反射对象,再通过反射对象的getParameterizedType()方法获取本参数的类型的Type对象,进行如上第 2.步骤及以后

或者

通过反射的方法Method对象,通过Method对象getGenericParameterTypes()方法,直接获取所有形参的类型组成的Type数组,再循环经过第 2.步骤及以后

package com.zmd.fanxingfanshe;

import java.lang.reflect.*;
import java.util.List;
import java.util.Map; /**
* @ClassName FanxingTest
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/17.
*/
public class FanxingTest {
//带泛型的属性(类变量或实例变量)
private Map<String, Integer> data;
private String string;
//定义带泛型的方法
private static void fanxingMethod(Map<String, Integer> users, String list){ }
//测试获取泛型
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
//获取类
Class<FanxingTest> cls = FanxingTest.class;
//获取类变量
Field dataField = cls.getDeclaredField("data");
System.out.println("=========获取类变量泛型类型==============="); //输出data的类型interface java.util.Map
System.out.println("data 的类型:" + dataField.getType()); //获取对应的带泛型类型
Type gtype = dataField.getGenericType();
System.out.println("参数类型:" + gtype); //java.util.Map<java.lang.String, java.lang.Integer>
if (gtype instanceof ParameterizedType){
//将Type对象强制类型转换为ParameterizedType对象
ParameterizedType ptype = (ParameterizedType) gtype;
System.out.println(ptype);
System.out.println(gtype + "的原始类型:" + ptype.getRawType());
//获取对应的泛型的类型
Type[] tTypes = ptype.getActualTypeArguments();
for (Type tType : tTypes){
System.out.println(tType);
}
} /**
* 获取方法形参的泛型
*/
System.out.println("=========通过反射获取方法,再通过方法getGenericParameterTypes获取形参泛型类型:===============");
//输入方法名和参数的类列表,获取具体方法的反射
Method fxMethod = cls.getDeclaredMethod("fanxingMethod", Map.class, String.class);
//设置private类型方法可访问
fxMethod.setAccessible(true);
//获取所有参数类型列表
Type[] parameterTypes = fxMethod.getGenericParameterTypes();
for (Type type: parameterTypes){
//当前参数类型
System.out.println("参数类型" + type);
if (type instanceof ParameterizedType){
ParameterizedType ptype = (ParameterizedType) type;
//原始类型
System.out.println("参数原始类型:" + ptype.getRawType());
//获取对应泛型的类型
Type[] types = ptype.getActualTypeArguments();
for (Type tType: types){
System.out.println(tType);
}
}
} //通过反射参数自身反射泛型
System.out.println("=========通过反射获取方法,再通过方法获取参数反射,再通过参数.getParameterizedType()获取形参泛型类型:===============");
Parameter[] parameters = fxMethod.getParameters();
for (Parameter parameter : parameters){
System.out.println("获取到参数:" + parameter.getName());
Type type = parameter.getParameterizedType();
System.out.println(parameter.getName() + "参数的类型:" + type);
if (type instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) type;
System.out.println(parameter.getName() + "参数的原始类型:"+ parameterizedType.getRawType());
Type[] types = parameterizedType.getActualTypeArguments();
for (Type type1 : types){
System.out.println(type1);
}
}
}
}
}

输出

=========获取类变量泛型类型===============
data 的类型:interface java.util.Map
参数类型:java.util.Map<java.lang.String, java.lang.Integer>
java.util.Map<java.lang.String, java.lang.Integer>
java.util.Map<java.lang.String, java.lang.Integer>的原始类型:interface java.util.Map
class java.lang.String
class java.lang.Integer
=========通过反射获取方法,再通过方法getGenericParameterTypes获取形参泛型类型:===============
参数类型java.util.Map<java.lang.String, java.lang.Integer>
参数原始类型:interface java.util.Map
class java.lang.String
class java.lang.Integer
参数类型class java.lang.String
=========通过反射获取方法,再通过方法获取参数反射,再通过参数.getParameterizedType()获取形参泛型类型:===============
获取到参数:arg0
arg0参数的类型:java.util.Map<java.lang.String, java.lang.Integer>
arg0参数的原始类型:interface java.util.Map
class java.lang.String
class java.lang.Integer
获取到参数:arg1
arg1参数的类型:class java.lang.String Process finished with exit code 0

java 编程基础 反射方式获取泛型的类型Fileld.getGenericType() 或Method.getGenericParameterTypes(); (ParameterizedType) ;getActualTypeArguments()的更多相关文章

  1. Java编程基础-反射

    一.java反射 1.反射:动态获取类的信息,以及动态调用对象的方法的功能.可以理解为动态看透类的能力. 2.主要功能:在运行时判断任意一个对象所属的类:在运行时构造任意一个类的对象:在运行时判断任意 ...

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

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

  3. JAVA基础_反射获取泛型参数类型

    我经常会想获取参数的实际类型,在Hibernate中就利用的这一点. domain: Person.java public class Person { // 编号 private Long id; ...

  4. Java框架基础——反射(reflect)

    一.Class类的使用 1)在面向对象(oop)的世界里,万事万物皆对象. 在Java中,包括基本的数据类型,都是对象. Class c = int.class;//int 的类类型 那就是说: 类是 ...

  5. Java 高级基础——反射

    Java 高级基础--反射 反射的意义:Java 强类型语言,但是我们在运行时有了解.修改信息的需求,包括类信息.成员信息以及数组信息. 基本类型与引用类型 基本类型,(固定的 8 种) 整数:byt ...

  6. Java编程基础-面向对象(中)

    本章承接Java编程基础-面向对象(上)一文. 一.static关键字 在java中,定义了一个static关键字,它用于修饰类的成员,如成员变量.成员方法以及代码块等,被static修饰的成员具备一 ...

  7. Java入门——(1)Java编程基础

    Java入门--(1)Java编程基础 第二章 Java编程基础   JAVA 代码的基本格式: 修饰符 class 类名{ 程序代码 }   2.1关键字:赋予了特殊含义的单词.   2.2标识符: ...

  8. Java开发知识之Java编程基础

    Java开发知识之Java编程基础 一丶Java的基础语法 每个语言都有自己的语法规范.例如C++ 入口点是main. 我们按照特定格式编写即可. Java也不例外. Java程序的语法规范就是 Ja ...

  9. 反射方式,获取出集合ArrayList类的class文件对象

    /* * 定义集合类,泛型String * 要求向集合中添加Integer类型 * * 反射方式,获取出集合ArrayList类的class文件对象 * 通过class文件对象,调用add方法 * * ...

随机推荐

  1. CF1540B Tree Array

    先写一下自己想到的部分: 考虑枚举一个根. 计算一个点对出现的概率. 对于我这种期望概率基本不会的人,差点就把这题切了. 自己想到的部分都没有假. 问题在于: 如何计算一个点对出现的概率. 考虑和这两 ...

  2. 洛谷 P6222 - 「P6156 简单题」加强版(莫比乌斯反演)

    原版传送门 & 加强版传送门 题意: \(T\) 组数据,求 \(\sum\limits_{i=1}^n\sum\limits_{j=1}^n(i+j)^k\mu^2(\gcd(i,j))\g ...

  3. 如何构建自己的KEGG数据库

    本文转自Y叔公众号 自己KEGG数据库好处: 可重复性好 没网也可以进行分析 步骤 1 在KEGG官网找到自己物种的3字符缩写 2 加载Y叔获取kegg.db 的R包 1 ##安装Y叔的包 2 lib ...

  4. bwa比对软件的使用以及其结果文件(sam)格式说明

    一.bwa比对软件的使用 1.对参考基因组构建索引 bwa index -a bwtsw hg19.fa   #  -a 参数:is[默认] or bwtsw,即bwa构建索引的两种算法,两种算法都是 ...

  5. Excel—在Excel中利用宏定义实现MD5对字符串(如:手机号)或者文件加密

    下载宏文件[md5宏] 加载宏 试验md5加密 可能遇到的问题 解决办法 下载宏文件[md5宏] 下载附件,解压,得md5宏.xla md5宏.zip 加载宏 依次打开[文件]-[选项]-[自定义功能 ...

  6. SM 国密算法踩坑指南

    各位,好久不见~ 最近接手网联的国密改造项目,由于对国密算法比较陌生,前期碰到了一系列国密算法加解密的问题. 所以这次总结一下,分享这个过程遇到的问题,希望帮到大家. 国密 什么是国密算法? 国密就是 ...

  7. 日常Java 2021/10/12

    封装 在面向对象程式设计方法中,封装是指-种将抽象性函式接口的实现细节部分包装.隐藏起来的方法 封装可以被认为是一个保护屏障,防止该类的代码和数据被外部类定义的代码随机访问 要访问该类的代码和数据,必 ...

  8. 日常Java 2021/9/21

    将Java数组中的元素前后反转.题目要求:已知一个数组arr = {11,12,13,14,15}用程序实现把该数组中的元素值交换,交换后的数组arr = { 15,14,13,12,11},并输出交 ...

  9. 零基础学习java------day4------流程控制结构

    1. 顺序结构 代码从上往下依次执行 2. 选择结构 也叫分支结构,其会根据执行的结果选择不同的代码执行,有以下两种形式: if  语句 switch  语句 2.1 if 语句 2.1.1  if语 ...

  10. Shell学习(七)——sort、uniq、cut、wc命令详解

    Shell学习(七)--sort.uniq.cut.wc命令详解 转自:[1]linux sort,uniq,cut,wc命令详解 https://www.cnblogs.com/ggjucheng/ ...