黑马程序员_java反射机制解析

来源:互联网 发布:扬州爬山虎科技 java 编辑:程序博客网 时间:2024/05/23 11:13

                                                                                   -------android培训java培训、期待与您交流! ----------

java反射机制

JAVA反射机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,PerlPythonRuby是动态语言,C++JavaC#不是动态语言。但是JAVA有着一个非常突出的动态相关机制:Reflection,用在Java身上指的是我们可以于运行时加载、探知、使用编译期间完全未知的classes。换句话说,Java程序可以加载一个运行时才得知名称的class,获悉其完整构造(但不包括methods定义),并生成其对象实体、或对其fields设值、或唤起其methods

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

Java反射机制主要提供了以下功能:在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

1、反射的概念

反射的引入:

             Object obj = new Student();

              若程序运行时接收到外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行类型的方法:

              1.若编译和运行类型都知道,使用 instanceof判断后,强转。

              2.编译时根本无法预知该对象属于什么类,程序只能依靠运行时信息来发现对象的真实信息,这时就必须使用反射了。

              3.要是想得到对象真正的类型,就得使用反射。

什么是反射机制? 

        简单的来说,反射机制指的是程序在运行时能够获取自身的信息。在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息。

反射机制的优点与缺点: 

          为什么要用反射机制?直接创建对象不就可以了吗,这就涉及到了动态与静态的概念。 

           静态编译:在编译时确定类型,绑定对象 

           动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。 

           一句话,反射机制的优点就是可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发。

它的缺点是对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。

 Class类和Class类实例

Java程序中的各个Java类属于同一类事物,描述这类事物的Java类就是Class类。

那么就有这样的问题:众多的人用一个什么类表示?众多的Java类用一个什么类表示?

  Person                 Java  Class

如果Person类代表人,它的实例对象就是张三,李四这样一个个具体的人,Class类代表Java类,它的各个实例对象又分别对应什么呢?

对应各个类在内存中的字节码,例如,Person类的字节码,ArrayList类的字节码等等;

一个类被类加载器加载到内存中,占用一片存储空间,这个空间里面的内容就是类的字节码,不同的类的字节码是不同的,所以它们在内存中的内容是不同的;

用类来描述对象,类:描述数据的结构;

用元数据(MetaData)来描述Class描述数据结构的结构,而这些所谓的元数据指的就是java类;

反射就是运用面向对象的思想把Java类中的各种成分映射成相应的java类(元数据)。

反射就是得到元数据的行为;

备注:一个类在虚拟机中只有一份字节码;

2、获得Class对象

 如何得到各个字节码对应的实例对象?

每个类被加载后,系统会为该类生成对应的Class对象,通过Class对象可以访问到JVM中的这个类。

其中Class对象的获得有如下3种方式:

1)、调用某个类的class属性获取Class对象,如Date.class会返回Date类对应的Class对象(其实就是得到一个类的一份字节码文件)

2)、使用Class类的forName(String className)静态方法,className表示全限定名;如String的全限定名:java.lang.Strin;;

3)、调用某个对象的getClass()方法。该方法属于Object类;

Class<?> clz = new Date().getClass();

eg:package com.demo.reflect;public class ClassDemo1 {       public static void main(String[] args) throws Exception {              //获得Class对象的方法(三种)              //一:调用属性              Class<String> c = String.class;              System.out.println(c);//打印结果:class java.lang.String,String.class就表示JVM中一份表示String类的字节码              Class<String> c2 = String.class;              System.out.println(c == c2);//true都是String类的字节码            一个类在虚拟机中只有一份字节码;                            //二:使用forName()方法              //Class cla = Class.forName("String");//ERROR,              Class<String> cla = (Class<String>)Class.forName("java.lang.String");//必须用上全限定名,否则报错              System.out.println(c == cla);//true                            //三:利用对象调用Object的getClass方法;              Class c3 = new String().getClass();              System.out.println(c == c3);//ture       }}


3、九个预定义Class对象

基本的 Java类型(booleanbytecharshortintlongfloat double)和关键字 void通过class属性也表示为 Class对象;

Class类中boolean isPrimitive() :判定指定的 Class对象是否表示一个基本类型。

包装类和Void类的静态TYPE字段;

Integer.TYPE == int.class ;         

Integer.class == int.class;             

 数组类型的Class实例对象:

Class<String[]> clz = String[].class;

数组的Class对象如何比较是否相等?数组的维数和数组的类型;

Class类中 boolean isArray():判定此 Class 对象是否表示一个数组类型。

package com.demo.reflect;public class PreClassDemo2 {       public static void main(String[] args) {              Class<?> in = int.class;              System.out.println(in);//int              Class<?> in2 = Integer.class;              //包装类都有一个常量TYPE,用来表示其基本数据类型的字节码              Class<?> in3 = Integer.TYPE;              System.out.println(in2);//class java.lang.Integer              System.out.println(in3);//int              System.out.println(in3 == in);//true包装类都有一个常量TYPE,用来表示其基本数据类型的字节码,所以这里会相等!              System.out.println(in3 == in2);//false              Class<String[]> s = String [].class;              Class<int[]> i = int [].class;              //System.out.println(i ==s);//编译根本就通过不了,一个是int,一个是String       }       //这两个自定义的方法是可以的,一个int,一个Integer//包装类与基本数据类型的字节码是不一样的       public void show(int i){}       public void show(Integer i){}}

4、利用Class获取类的属性信息

package com.demo.reflect;import java.lang.reflect.Modifier;class A {  }interface B{}interface C{}public class BaseDemo3 extends A implements B,C{       //内部类       public class C{}       public interface D{}       public static void main(String[] args) {              //类可以,接口也可以              Class<BaseDemo3> c = BaseDemo3.class;              System.out.println(c);//class com.demo.reflect.BaseDemo3              //得到包名              System.out.println(c.getPackage());//package com.demo.reflect              //得到全限定名              System.out.println(c.getName());//com.demo.reflect.BaseDemo3              //得到类的简称              System.out.println(c.getSimpleName());//BaseDemo3              //得到父类              /*                 Class<? super T> getSuperclass()此处super表示下限                    返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。               */              System.out.println(c.getSuperclass().getSimpleName());//A,先获取父类,再获取父类的简称              //得到接口              System.out.println(c.getInterfaces());//[Ljava.lang.Class;@1b60280              Class[] arr = c.getInterfaces();              for (Class cla : arr) {                     System.out.println(cla);//interface com.demo.reflect.B   interface com.demo.reflect.C              }              //获得public修饰的类              /*                Class<?>[] getClasses()                返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class对象所表示的类的成员的所有公共类和接口。(如果内部类前面没有加上public的话那么得不到!)               */              Class[] cl = c.getClasses();              System.out.println(cl.length);//在内部类没有加上public修饰的时候长度为0,加上就是2(获取的是公共的)              for (Class class1 : cl) {                     System.out.println(class1);              }              //获得修饰符              int i = c.getModifiers();              System.out.println(i);//常量值1表示public              System.out.println(Modifier.toString(i));//直接打印出public       }}

5Class中得到构造方法Constructor、方法Method、字段Field

常用方法:

Constructor类用于描述类中的构造方法:

Constructor<T> getConstructor(Class<?>... parameterTypes):返回该Class对象表示类的指定的public构造方法;

Constructor<?>[] getConstructors():返回该Class对象表示类的所有public构造方法;

Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes):返回该Class对象表示类的指定的构造方法,和访问权限无关;

Constructor<?>[] getDeclaredConstructors():返回该Class对象表示类的所有构造方法,和访问权限无关;

 

Method类用于描述类中的方法:

Method getMethod(String name, Class<?> ... parameterTypes):返回该Class对象表示类和其父类的指定的public方法;

Method[] getMethods() 返回该Class对象表示类和其父类的所有public方法;

Method getDeclaredMethod(String name, Class<?>... parameterTypes):返回该Class对象表示类的指定的方法。和访问权限无关,但不包括继承的方法;

Method[] getDeclaredMethods():获得类所有的方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法;

eg:package com.demo.reflect;import java.lang.reflect.Constructor;class Emp{       private String name;       private int age;       private Emp() {       }        Emp(String name){       }       public Emp(String name,int age){       }}public class ConstructorDemo4 {       public static void main(String[] args) throws Exception {              //得到所有的构造器(先得到类)              Class<Emp> c = Emp.class;              /*                Constructor<?>[] getConstructors()                返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class对象所表示的类的所有公共构造方法。               */              Constructor[] con = c.getConstructors();//前面的修饰符必须是public才可以在这个方法下获取到              for (Constructor cons : con) {                     System.out.println("c.getConstructors()"+cons);//如果上面的某构造器public去掉,则显示不出                     /*打印                            public com.demo.reflect.Emp(java.lang.String,int)                      */              }              //得到指定的构造器,也是必须public              Constructor c1 = c.getConstructor(String.class,int.class);              System.out.println(c1);//public com.demo.reflect.Emp(java.lang.String,int)              System.out.println("====================================");             //现在想获得不受public影响的,getDeclaredConstructors(),暴力反射              con = c.getDeclaredConstructors();              for (Constructor cons : con) {                   System.out.println("c.getDeclaredConstructors()=="+cons);//此时不受修饰符的影响                     /*打印                        public com.demo.reflect.Emp()                     public com.demo.reflect.Emp(java.lang.String)                     public com.demo.reflect.Emp(java.lang.String,int)                   */              }       }}

 

package com.demo.reflect;import java.lang.annotation.Annotation;import java.lang.reflect.Field;import java.lang.reflect.Method;class AB{       protected String name;       protected String id;}@Deprecatedpublic class MethodDemo5 extends AB{       void show(){}       public void say(){}       private int age;       public char c;       private boolean b;       public static void main(String[] args) throws Exception {              Class<MethodDemo5> c = MethodDemo5.class;              //获取所有的(包含父类的方法)public修饰的方法              Method[] m = c.getMethods();              for (Method method : m) {                     System.out.println(method);              }              //总结:4个方法,获取全部,获取特定;不受修饰符影响的全部,不受修饰符影响的特定;(前两个都还是受限制的)              //获取指定的方法              Method me = c.getMethod("main", String[].class);              System.out.println("main "+me);//main public static void com.demo.reflect.MethodDemo5.main(java.lang.String[]) throws java.lang.Exception              //访问所有方法,不受访问权限影响              m = c.getDeclaredMethods();              for (Method method : m) {                     System.out.println("不受影响的:"+method);              }                            me = c.getDeclaredMethod("show");              System.out.println(me);//void com.demo.reflect.MethodDemo.show()              me = c.getMethod("toString");              System.out.println(me);//public java.lang.String java.lang.Object.toString()              /*                Method[] getDeclaredMethods()                       返回 Method 对象的一个数组,这些对象反映此 Class对象表示的类或接口声明的所有方法,                       包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法,只可以对当前类有效               */              /*me = c.getDeclaredMethod("toString");//ERROR,c.getDeclaredMethod()不能得到继承的方法              System.out.println(me);//public java.lang.String java.lang.Object.toString()               */                 //得到字段              Field[] f = c.getFields();              for (Field field : f) {//只得到了public的                     System.out.println("字段"+field);              }                            //特定字段              Field fi = c.getField("c");//""里面是名称              System.out.println(fi);//public char com.demo.reflect.MethodDemo.c             //得到不受限定名限定的全部字段              f = c.getDeclaredFields();              for (Field field : f) {//得到不受修饰符限定的字段,但是只对当前类有效                     System.out.println("全部字段:"+field);                     /*                      全部字段:private int com.demo.reflect.MethodDemo.age                           全部字段:public char com.demo.reflect.MethodDemo.c                           全部字段:private boolean com.demo.reflect.MethodDemo.b                      */              }              //注释  Annotation               Annotation[] a = c.getAnnotations();               System.out.println(a.length);               for (Annotation annotation : a) {                     System.out.println(annotation);              }              //特定注解               Deprecated d = c.getAnnotation(Deprecated.class);               System.out.println(d);       }}
//获取当前对象的字段package com.demo.enhance;import java.lang.reflect.Field;class Stu{       public String name;       public String sex;       public int age;       public Stu(String name, String sex, int age) {              super();              this.name = name;              this.sex = sex;              this.age = age;       }}public class ReflectDemo6 {       public static void main(String[] args) throws Exception {              Stu s = new Stu("zhangsan", "男", 12);              Class<Stu> c = Stu.class;              Field f = c.getField("name");              System.out.println(f.get(s));////从哪个对象身上取!此时显示zhangsan!                 //     修改对象的值            /*  Field f = c.getField("name");              f.set(s,"lisi");              System.out.println(f.get(s));//从哪个对象身上取!//此时显示lisi*/       }}

6、利用反射创建对象

创建对象:

1、使用Class对象的newInstance()方法创建该Class对象的实例,此时该Class对象必须要有无参数的构造方法。

2、使用Class对象获取指定的Constructor对象,再调用ConstructornewInstance()方法创建对象类的实例,此时可以选择使用某个构造方法。如果这个构造方法被私有化起来,那么必须先申请访问,将可以访问设置为true

eg://最简单的:package com.demo.reflect;class User{       /*private User(){//将默认的构造方法私有化的话就不可以再创建对象,两种方法都是这样       }*/       public String toString() {              return "User对象创建成功!";       }}public class NewInstanceDemo1 {       public static void main(String[] args) throws Exception {              //传统方式创建对象               System.out.println(new User());              //使用反射的方式               Class<User> c = User.class;               User u = c.newInstance();(直接newInstance的话必须保证默认的构造方法正常存在,也就是没有被私有化!这是前提条件)               System.out.println(u);       }}

使用指定构造方法来创建对象:

获取该类的Class对象。

利用Class对象的getConstructor()方法来获取指定的构造方法。

调用ConstructornewInstance()方法创建对象。

 AccessibleObject对象的setAccessible(boolean flag)方法,flagtrue的时候,就会忽略访问权限(可访问私有的成员)

其子类有Field, Method, Constructor;

若要访问对象private的成员?

在调用之前使用setAccessible(true),

       Xxx x = getDeclaredXxxx();//才能得到私有的类字段。

 总结步骤:

1.    获取该类的Class对象。

2.    利用Class对象的getConstructor()方法来获取指定的构造方法。

3.    申请访问(设置为可访问)。

4.    调用Constructor(构造方法)的newInstance()方法创建对象。

 eg:package com.demo.reflect;import java.lang.reflect.Constructor;class Per{       private String name;       private int age;       private Per(){       }       private Per(String name){       }       public String toString() {              return "对象!!!";       }}public class NewInstanceDemo2{       public static void main(String[] args) throws Exception {              Class<Per> c = Per.class;              //System.out.println(c.newInstance());;//证明利用无参的可以              ////先获得需要被调用的构造器(private修饰的构造方法)              Constructor<Per> con = c.getDeclaredConstructor();//调用默认的,什么都不要写              System.out.println(con);//private com.demo.reflect.Per()              /*con = c.getDeclaredConstructor(String.class);获取指定的构造方法              System.out.println(con);//private com.demo.reflect.Per(java.lang.String)*/                          //现在只需要执行这个构造器,              /**               *  T newInstance(Object... initargs)                          使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。               */             //私有的成员是受保护的,不能直接访问              //若要访问私有的成员,得先申请一下              con.setAccessible(true);//允许访问              Per p = con.newInstance();//成功,通过私有的受保护的构造方法创建了对象              System.out.println("无参构造方法"+p);              con = c.getDeclaredConstructor(String.class);              System.out.println(con);//private com.demo.reflect.Per(java.lang.String)               con.setAccessible(true);//允许访问              p = con.newInstance("liuzhao");//成功,通过私有的受保护的构造方法创建了对象              System.out.println("String构造方法"+p);       }}

备注:对于此时的话,单例模式就不再安全了!反射可破之!!

验证:对于枚举而言,反射依然没有办法重新创建对象,对于枚举,安全!

package com.demo.reflect;import java.lang.reflect.Constructor;enum Color{       RED,BLUE,GREEN;       private Color(){       }}public class EnumDemo {       public static void main(String[] args) throws Exception {              Class<Color> c = Color.class;              Constructor<Color> con = c.getDeclaredConstructor();//(错误在这一行发生,就是说对枚举而言这种方法连构造器都获得不了,)编译可以通过,但是运行就通不过了!              Color co = (Color) con.newInstance();              System.out.println(co);//失败,证明对枚举而言不行,所以枚举的单例模式更加安全              System.out.println(c.isEnum());//true是枚举       }}

7、使用反射调用方法

每个Method的对象对应一个具体的底层方法。获得Method对象后,程序可以使用Method里面的invoke方法来执行该底层方法。

Object invoke(Object obj,Object ... args):obj表示调用底层方法的对象,后面的args表示传递的实际参数。

如果底层方法是静态的,那么可以忽略指定的 obj参数。该参数可以为 null,想想为什么?

如果底层方法所需的形参个数为 0,则所提供的 args数组长度可以为 0 null

不写,null, new Object[]{}

若底层方法返回的是数组类型,invoke方法返回的不是底层方法的值,而是底层方法的返回类型; 

package com.demo.reflect;import java.lang.reflect.Method;class Dept{       public String show(String name){//用反射的方法来调用正常的方法              return name+",您好!";       }       private void privateshow(){//用反射来实现对私有化方法的调用              System.out.println("privateshow");       }       public static void staticshow(){              System.out.println("staticshow");       }}public class InvokeDemo9 {       public static void main(String[] args) throws Exception {           /*    传统方式:              String name = new Dept().show("zhangsan");              System.out.println(name);*/                Method getMethod(String name, Class<?>... parameterTypes)                    返回一个 Method 对象,它反映此 Class对象所表示的类或接口的指                   定公共成员方法。                  name -方法名                     parameterTypes -参数列表               */              //想要通过反射来调用Dept中的方法              Class<Dept> c = Dept.class;              Method m = c.getMethod("show", String.class);              Object o = m.invoke(c.newInstance(), "zhangsan");              System.out.println(o);             //私有化的方法              m = c.getDeclaredMethod("private show");//无参方法              m.setAccessible(true);              o = m.invoke(c.newInstance());             //静态方法的调用              m = c.getMethod("static show");              m.invoke(null);//staticshow为静态方法,不需创建对象,所以这里会是null       }}打印zhangsan,您好!private showstatic show

8、使用反射调用可变参数方法

使用反射操作对象-调用可变参数方法

要把可变参数都当做是其对应的数组类型参数;

show(XX... is)作为show(XX[] is)调用;

 若可变参数元素类型是引用类型:

JDK内部接收到参数之后,会自动拆包取出参数再分配给该底层方法,为此我们需要把这个数组实参先包装成一个Object对象或把实际参数作为一个Object一维数组的元素再传递。

 若可变参数元素类型是基本类型:

JDK内部接收到参数之后,不会拆包,所以可以不必再封装,不过封装了也不会错。所以建议,不管基本类型还是引用类型都使用Object[]封装一层,保证无误。

eg:package com.demo.reflect;//可变参数的方法调用import java.lang.reflect.Method;class VaryMethod{       public static void show(int ...args){              System.out.println("基本数据类型传递过来了!");       }       /*public static void show(int[] args){//这是一样的       }*/       public static void show(String ...args){              System.out.println("引用数据类型传递过来了!");       }}public class InvokeVaryDemo10 {       public static void main(String[] args) throws Exception{              Class<VaryMethod> c = VaryMethod.class;              Method m = c.getMethod("show",int[].class);              m.invoke(null,new int[]{1,2,3});              m = c.getMethod("show",String[].class);              //m.invoke(null,new String[]{"A","B","C"});//ERROR              m.invoke(null,(Object)new String[]{"A","B","C"});//YES,强转为Object类型              m.invoke(null,new Object[]{new String[]{"A","B","C"}});//推荐写法       }}

9、使用反射操作字段

Field提供两组方法操作字段:

xxx getXxx(Object obj):获取obj对象该Field的字段值,此处的xxx表示8个基本数据类型。若该字段的类型是引用数据类型则使用,Object get(Object obj);

void setXxx(Object obj,xxx val):obj对象的该Field字段设置成val值,此处的xxx表示8个基本数据类型。若该字段的类型是引用数据类型则使用,void set(Object obj, Object value); 

package com.demo.reflect;/*获取字符,并且赋值,然后再取出来(对应的去查看api,比如这个是Field,别的比如Constructor,Method)步骤:1.获取类2.获取字段3.赋值(set(c.newInstance(),””));{如果为私有的话设置可接受}*/import java.lang.reflect.Field;class Cat{       private String name;       public int age;       private String color;}public class FieldDemo {       public static void main(String[] args) throws Exception {              Class<Cat> clz = Cat.class;              Field[] f = clz.getDeclaredFields();              for (Field field : f) {                     System.out.println(field);              }              Field fi = clz.getDeclaredField("name");              System.out.println(fi);              System.out.println(fi.getName());//name              //核心开始              /*                 void set(Object obj, Object value)将指定对象变量上此 Field对象表示的字段设置为指定的新值。               */              Cat c = clz.newInstance();              fi.setAccessible(true);              fi.set(c, "zhangsan");//赋值成功              Object o = fi.get(c);              System.out.println(o);//取出成功              fi = clz.getDeclaredField("age");              fi.setAccessible(true);              fi.set(c, 21);              int i = fi.getInt(c);//左边的接受类型已经写成了int,右边的返回类型就也必须是int              System.out.println(i);//获取成功       }}打印private java.lang.String com.demo.reflect.Cat.namepublic int com.demo.reflect.Cat.ageprivate java.lang.String com.demo.reflect.Cat.colorprivate java.lang.String com.demo.reflect.Cat.namenamezhangsan21

10、反射和泛型-反射来获取泛型信息

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

Class<?> type = f.getType();//获得字段的类型

但此方法只对普通Field有效,若该Field有泛型修饰,则不能准确得到该Field的泛型参数,Map<String,Integer>;

为了获得指定Field的泛型类型,我们采用:

Type gType = f.getGenericType();得到泛型类型

然后将Type对象强转为ParameterizedType,其表示增加泛型后的类型;

Type getRawType()//返回被泛型限制的类型;

Type[]  getActualTypeArguments()//返回泛型参数类型;

利用反射来获取泛型的类型(泛型信息)

步骤:

1.获取当前类;

2.获取目标字段;

3.获取包含泛型类型的类型 getGenericType();

4.强转至子类ParameterizedType    因为Type没有任何对应的方法;

5.获得泛型真正的类型 getActualTypeArguments();

eg: package com.demo.reflect;import java.lang.reflect.Field;import java.lang.reflect.ParameterizedType;import java.lang.reflect.Type;import java.util.HashMap;import java.util.Map;public class GetGenericTypeDemo14 {       Map<String,Integer> map = new HashMap<String,Integer>();       public static void main(String[] args) throws Exception {              Class c = GetGenericTypeDemo14.class;              Field f = c.getDeclaredField("map");              System.out.println(f);              System.out.println(f.getName());//map              // Class<?> getType() 返回一个 Class 对象,它标识了此 Field对象所表示字段的声明类型。              Class cl = f.getType();              System.out.println("获得其类型:"+cl);             //获得其类型:interface java.util.Map              /*                Type getGenericType()返回一个 Type 对象,它表示此 Field对象所表示字段的声明类型。                  Type是Class的接口;               */              Type t = f.getGenericType();//包含泛型的类型              System.out.println(t);            //java.util.Map<java.lang.String, java.lang.Integer>               /*                Type这个类里面没有任何的方法,所以需要调用子类的方法,那么大的类型转到小的类型,需要强转!               */              ParameterizedType pt = (ParameterizedType)t;//强转到其子类              /*                  Type[] getActualTypeArguments()                              返回表示此类型实际类型参数的 Type对象的数组。                      Type getOwnerType()                              返回 Type 对象,表示此类型是其成员之一的类型。                      Type getRawType()                              返回 Type 对象,表示声明此类型的类或接口。               */              t = pt.getRawType();//类型的类或接口              System.out.println(t);                            Type[] ts = pt.getActualTypeArguments();              for (Type type : ts) {                     System.out.println(type);                     /*                         class java.lang.String                         class java.lang.Integer                      */              }       }}打印:java.util.Map com.demo.reflect.GetGenericTypeDemo14.mapmap获得其类型:interface java.util.Mapjava.util.Map<java.lang.String, java.lang.Integer>interface java.util.Mapclass java.lang.Stringclass java.lang.Integer

0 0
原创粉丝点击