Java反射机制全解

反射的引入:

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类的字节码,等等;

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

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

用元数据来描述Class,MetaData(元数据):描述数据结构的结构;

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

 

 

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

 

获得Class对象

 

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

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

3种方式:

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

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

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

Class clz = new Date().getClass();


 
 
   
   
   
   
  1. public class ClassDemo1 {
  2.    public static void main(String[] args) throws Exception {
  3.       //获得Class对象的方法(三种)
  4.       //一:调用属性
  5.       Class c = String.class;
  6.       System.out.println(c); //打印结果:class java.lang.String          String.class就表示JVM中一份表示String类的字节码
  7.       Class c2 = String.class;
  8.       System.out.println(c == c2); //true都是String类的字节码        一个类在虚拟机中只有一份字节码;
  9.      
  10.       //二:使用forName()方法
  11.       //Class cla = Class.forName("String");//ERROR,
  12.       Class cla =  (Class)Class.forName( "java.lang.String"); //必须用上全限定名,否则报错
  13.       System.out.println(c == cla); //true
  14.      
  15.       //三:利用对象调用Object的getClass方法;
  16.       Class c3 = new String().getClass();
  17.       System.out.println(c == c3); //ture
  18.    }
  19. }

 

我的总结:获取Class对象最常用的是利用属性的方法!

九个预定义Class对象

 

基本的 Java 类型(boolean、byte、char、short、int、long、float 、double)和关键字void通过class属性也表示为 Class 对象;

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

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

Integer.TYPE == int.class ;         

Integer.class == int.class;      

 数组类型的Class实例对象:

Class clz = String[].class;

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

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


 
 
   
   
   
   
  1. public class PreClassDemo2 {
  2.    public static void main(String[] args) {
  3.       Class in = int.class;
  4.       System.out.println(in); //int
  5.       Class in2 = Integer.class;
  6.       //包装类都有一个常量TYPE,用来表示其基本数据类型的字节码
  7.       Class in3 = Integer.TYPE;
  8.       System.out.println(in2); //class java.lang.Integer
  9.       System.out.println(in3); //int
  10.       System.out.println(in3 == in); //true 包装类都有一个常量TYPE,用来表示其基本数据类型的字节码,所以这里会相等!
  11.       System.out.println(in3 == in2); //false
  12.       Class s = String [].class;
  13.       Class< int[]> i = int [].class;
  14.       //System.out.println(i ==s);//编译根本就通过不了,一个是int,一个是String
  15.    }
  16.    //这两个自定义的方法是可以的,一个int,一个Integer//包装类与基本数据类型的字节码是不一样的
  17.    public void show(int i){}
  18.    public void show(Integer i){}
  19. }

利用Class获取类的属性信息

import java.lang.reflect.Modifier;
 


 
 
   
   
   
   
  1. class A {
  2. }
  3. interface B{
  4. }
  5. interface C{
  6. }

 
 
   
   
   
   
  1. public class BaseDemo3 extends A implements B,C{
  2.    //内部类
  3.    public class C{}
  4.    public interface D{}
  5.    public static void main(String[] args) {
  6.       //类可以,接口也可以
  7.       Class c = BaseDemo3.class;
  8.       System.out.println(c); //class junereflect624.BaseDemo3
  9.       //得到包名
  10.       System.out.println(c.getPackage()); //package junereflect62;
  11.       //得到全限定名
  12.       System.out.println(c.getName()); //junereflect624.BaseDemo3
  13.       //得到类的简称
  14.       System.out.println(c.getSimpleName()); //BaseDemo3
  15.       //得到父类
  16.       /**
  17.        * Class getSuperclass() 此处super表示下限
  18.                返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的 Class。
  19.        */
  20.       System.out.println(c.getSuperclass().getSimpleName()); //A,先获取父类,再获取父类的简称
  21.       //得到接口
  22.    System.out.println(c.getInterfaces()); //[Ljava.lang.Class;@1b60280
  23.       Class[] arr = c.getInterfaces();
  24.       for (Class cla : arr) {
  25.          System.out.println(cla); //interface junereflect624.B   interface junereflect624.C
  26.       }
  27.       //获得public修饰的类
  28.       /**
  29.        * Class[] getClasses()
  30.                 返回一个包含某些 Class 对象的数组,这些对象表示属于此 Class 对象所表示的类的成员的所有公共类和接口。 (如果内部类前面没有加上public的话那么得不到!)
  31.        */
  32.       Class[] cl = c.getClasses();
  33.       System.out.println(cl.length); //在内部类没有加上public修饰的时候长度为0,加上就是2(获取的是公共的)
  34.       for (Class class1 : cl) {
  35.          System.out.println(class1);
  36.       }
  37.       //获得修饰符
  38.       int i = c.getModifiers();
  39.       System.out.println(i); //常量值1表示public
  40.       System.out.println(Modifier.toString(i)); //直接打印出public
  41.    }
  42. }

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

常用方法:

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

Constructor getConstructor(Class... parameterTypes)

返回该Class对象表示类的指定的public构造方法;

Constructor[] getConstructors()

返回该Class对象表示类的所有public构造方法;

Constructor 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:

import java.lang.reflect.Constructor;


 
 
   
   
   
   
  1. class Emp{
  2.    private String name;
  3.    private int age;
  4.    private Emp() {
  5.    }
  6.    Emp(String name){
  7.    }
  8.    public Emp(String name,int age){
  9.    }
  10. }

 


 
 
   
   
   
   
  1. public class ConstructorDemo4 {
  2.    public static void main(String[] args) throws Exception {
  3.       //得到所有的构造器(先得到类)
  4.       Class c = Emp.class;
  5.       /**
  6.        * Constructor[] getConstructors()
  7.                返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
  8.        */
  9.       Constructor[] con = c.getConstructors(); //前面的修饰符必须是public才可以在这个方法下获取到
  10.       for (Constructor cons : con) {
  11.          System.out.println( "c.getConstructors()"+cons); //如果上面的某构造器public去掉,则显示不出
  12.          /**打印
  13.             public junereflect624.Emp(java.lang.String,int)
  14.           */
  15.       }
  16.       //得到指定的构造器,也是必须public
  17.       Constructor c1 = c.getConstructor(String.class, int.class);
  18.       System.out.println(c1); //public junereflect624.Emp(java.lang.String,int)
  19. System.out.println( "====================================");
  20.    //现在想获得不受public影响的,getDeclaredConstructors(),暴力反射
  21.      
  22.       con = c.getDeclaredConstructors();
  23.       for (Constructor cons : con) {
  24. System.out.println( "c.getDeclaredConstructors()=="+cons); //此时不受修饰符的影响
  25.          /**打印
  26.           *  public junereflect624.Emp()
  27.             public junereflect624.Emp(java.lang.String)
  28.             public junereflect624.Emp(java.lang.String,int)
  29.           */
  30.       }
  31.    }
  32. }

 

import java.lang.annotation.Annotation;

import java.lang.reflect.Field;

import java.lang.reflect.Method;


 
 
   
   
   
   
  1. class AB{
  2.    protected String name;
  3.    protected String id;
  4. }

 
 
   
   
   
   
  1. @Deprecated
  2. public class MethodDemo5 extends AB{
  3.    void show(){}
  4.    public void say(){}
  5.    private int age;
  6.    public char c;
  7.    private boolean b;
  8.    public static void main(String[] args) throws Exception {
  9.       Class c = MethodDemo5.class;
  10.       //获取所有的(包含父类的方法)public修饰的方法
  11.       Method[] m = c.getMethods();
  12.       for (Method method : m) {
  13.          System.out.println(method);
  14.       }
  15.       //总结:4个方法,获取全部,获取特定;不受修饰符影响的全部,不受修饰符影响的特定;(前两个都还是受限制的)
  16.       //获取指定的方法
  17.       Method me = c.getMethod( "main", String[].class);
  18.       System.out.println( "main "+me); //main public static void junereflect624.MethodDemo5.main(java.lang.String[]) throws java.lang.Exception
  19.       //访问所有方法,不受访问权限影响
  20.       m = c.getDeclaredMethods();
  21.       for (Method method : m) {
  22.          System.out.println( "不受影响的:"+method);
  23.       }
  24.       me = c.getDeclaredMethod( "show");
  25.       System.out.println(me); //void junereflect624.MethodDemo.show()
  26.       me = c.getMethod( "toString");
  27.       System.out.println(me); //public java.lang.String java.lang.Object.toString()
  28.       /**
  29.        * Method[] getDeclaredMethods()
  30.                 返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法,只可以对当前类有效
  31.        */
  32.       /*me = c.getDeclaredMethod("toString");//ERROR,c.getDeclaredMethod()不能得到继承的方法
  33.       System.out.println(me);//public java.lang.String java.lang.Object.toString()
  34.        */
  35.       //得到字段
  36.       Field[] f = c.getFields();
  37.       for (Field field : f) { //只得到了public的
  38.          System.out.println( "字段"+field);
  39.       }
  40.       //特定字段
  41.       Field fi = c.getField( "c"); //""里面是名称
  42.       System.out.println(fi); //public char junereflect624.MethodDemo.c
  43.       //得到不受限定名限定的全部字段
  44.       f = c.getDeclaredFields();
  45.       for (Field field : f) { //得到不受修饰符限定的字段,但是只对当前类有效
  46.          System.out.println( "全部字段:"+field);
  47.          /**
  48.           * 全部字段:private int junereflect624.MethodDemo.age
  49.           * 全部字段:public char junereflect624.MethodDemo.c
  50.           * 全部字段:private boolean junereflect624.MethodDemo.b
  51.           */
  52.       }
  53.       //注释  Annotation
  54.        Annotation[] a = c.getAnnotations();
  55.        System.out.println(a.length);
  56.         for (Annotation annotation : a) {
  57.          System.out.println(annotation);
  58.       }
  59.         //特定注解
  60.        Deprecated d = c.getAnnotation(Deprecated.class);
  61.        System.out.println(d);
  62.    }
  63. }

获取当前对象的字段:


 
 
   
   
   
   
  1. import java.lang.reflect.Field;
  2. class Stu{
  3.    public String name;
  4.    public String sex;
  5.    public int age;
  6.    public Stu(String name, String sex, int age) {
  7.       super();
  8.       this.name = name;
  9.       this.sex = sex;
  10.       this.age = age;
  11.    }
  12. }
  13. public class ReflectDemo6 {
  14.    public static void main(String[] args) throws Exception {
  15.       Stu s = new Stu( "刘昭", "男", 12);
  16.       Class c = Stu.class;
  17.       Field f = c.getField( "name");
  18.       System.out.println(f.get(s)); 从哪个对象身上取!此时显示刘昭!
  19. // 修改对象的值
  20. /**
  21. Field f = c.getField("name");
  22.       f.set(s,"章泽天");
  23. System.out.println(f.get(s));//从哪个对象身上取!//此时显示章泽天
  24. */
  25.    }
  26. }

我的总结:对于方法,字段,构造方法之类用类获取记住四个:获取全部,获取特定,暴力获取全部,暴力获取特定!

利用反射创建对象

创建对象:

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

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

Eg:

最简单的:


 
 
   
   
   
   
  1. class User{
  2. //将默认的构造方法私有化的话就不可以再创建对象,两种方法都是这样
  3.    /*private User(){}*/
  4.    public String toString() {
  5.       return "User对象创建成功!";
  6.    }
  7. }

 
 
   
   
   
   
  1. public class NewInstanceDemo6 {
  2.    public static void main(String[] args) throws Exception {
  3.       //传统方式创建对象
  4.        System.out.println( new User());
  5.         //使用反射的方式
  6.        Class c = User.class;
  7.        User u = c.newInstance();(直接newInstance的话必须保证默认的构造方法正常存在,也就是没有被私有化!这是前提条件)
  8.        System.out.println(u);
  9.    }
  10. }

复杂点的:更强大的第二种:

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

获取该类的Class对象。

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

调用Constructor的newInstance()方法创建对象。

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

其子类有Field, Method, Constructor;

若要访问对象private的成员?

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

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

总结步骤:

  1. 获取该类的Class对象。
  2. 利用Class对象的getConstructor()方法来获取指定的构造方法。
  3. 申请访问(设置为可访问)
  4. 调用Constructor(构造方法)的newInstance()方法创建对象。

例子

import java.lang.reflect.Constructor;


 
 
   
   
   
   
  1. class Per{
  2.    private String name;
  3.    private int age;
  4.    private Per(){  
  5.    }
  6.    private Per(String name){
  7.    }
  8.    public String toString() {
  9.       return "对象!!!";
  10.    }
  11. }

 
 
   
   
   
   
  1. public class NewInstanceDemo7 {
  2.    public static void main(String[] args) throws Exception {
  3.       Class c = Per.class;
  4.       //System.out.println(c.newInstance());;//证明利用无参的可以
  5.       先获得需要被调用的构造器(private 修饰的构造方法)
  6.       Constructor con = c.getDeclaredConstructor(); //调用默认的,什么都不要写
  7.       System.out.println(con); //private junereflect624.Per()
  8.       /*con = c.getDeclaredConstructor(String.class);获取指定的构造方法
  9.       System.out.println(con);//private junereflect624.Per(java.lang.String)*/    
  10.       //现在只需要执行这个构造器,
  11.       /**
  12.        *  T newInstance(Object... initargs)
  13.             使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
  14.        */
  15.       //私有的成员是受保护的,不能直接访问
  16.       //若要访问私有的成员,得先申请一下
  17.       con.setAccessible( true); //允许访问
  18.       Per p = con.newInstance(); //成功,通过私有的受保护的构造方法创建了对象
  19.       System.out.println( "无参构造方法"+p);
  20.       con = c.getDeclaredConstructor(String.class);
  21.       System.out.println(con); //private junereflect624.Per(java.lang.String);     
  22. con.setAccessible( true); //允许访问
  23.       p = con.newInstance( "liuzhao"); //成功,通过私有的受保护的构造方法创建了对象
  24.       System.out.println( "String构造方法"+p);
  25.    }
  26. }

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

使用反射调用方法

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

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

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

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

不写,null,或 new Object[]{}

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

import java.lang.reflect.Method;


 
 
   
   
   
   
  1. class Dept{
  2.    public String show(String name){ //用反射的方法来调用正常的方法
  3.       return name+ ",您好!";
  4.    }
  5.    private void privateshow(){ //用反射来实现对私有化方法的调用
  6.       System.out.println( "privateshow");
  7.    }
  8.    public static void staticshow(){
  9.       System.out.println( "staticshow");
  10.    }
  11. }

 
 
   
   
   
   
  1. public class InvokeDemo9 {
  2.    public static void main(String[] args) throws Exception {  
  3. /* 传统方式:
  4. String name = new Dept().show("刘昭");
  5.       System.out.println(name);*/    
  6. /**
  7.        * Method getMethod(String name, Class... parameterTypes)
  8.                返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指         定公共成员方法。
  9.           name - 方法名
  10.          parameterTypes - 参数列表
  11.        */
  12.       //想要通过反射来调用Dept中的方法
  13.       Class c = Dept.class;
  14.       Method m = c.getMethod( "show", String.class);
  15.       Object o = m.invoke(c.newInstance(), "刘昭");
  16.       System.out.println(o);
  17.     
  18.       //私有化的方法
  19.       m = c.getDeclaredMethod( "privateshow"); //无参方法
  20.       m.setAccessible( true);
  21.       o = m.invoke(c.newInstance());
  22.      
  23.       //静态方法的调用
  24.       m = c.getMethod( "staticshow");
  25.       m.invoke( null); //staticshow为静态方法,不需创建对象,所以这里会是null
  26.    }
  27. }

打印

刘昭,您好!

privateshow

staticshow

使用反射操作字段

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 junereflect624;

//获取字符,并且赋值,然后再取出来(对应的去查看api,比如这个是Field,别的比如Constructor,Method)

步骤:

  1. 获取类
  2. 获取字段
  3. 赋值(set(c.newInstance(),””));{如果为私有的话设置可接受}

import java.lang.reflect.Field;


 
 
   
   
   
   
  1. class Cat{
  2.    private String name;
  3.    public int age;
  4.    private String color;
  5. }

 
 
   
   
   
   
  1. public class FieldDemo12 {
  2.    public static void main(String[] args) throws Exception {
  3.       Class clz = Cat.class;
  4.       Field[] f = clz.getDeclaredFields();
  5.      
  6.       for (Field field : f) {
  7.          System.out.println(field);
  8.       }
  9.     
  10.       Field fi = clz.getDeclaredField( "name");
  11.       System.out.println(fi);
  12.     
  13.       System.out.println(fi.getName()); //name
  14.      
  15.       //核心开始
  16.       /**
  17.       *  void set(Object obj, Object value)
  18. 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。
  19.        */
  20.       Cat c = clz.newInstance();
  21.       fi.setAccessible( true);
  22.       fi.set(c, "刘昭"); //赋值成功
  23.       Object o = fi.get(c);
  24.       System.out.println(o); //取出成功
  25.      
  26.       fi = clz.getDeclaredField( "age");
  27.       fi.setAccessible( true);
  28.       fi.set(c, 21);
  29.       int i = fi.getInt(c); //左边的接受类型已经写成了int,右边的返回类型就也必须是int
  30.       System.out.println(i); //获取成功
  31.    }
  32. }

 

打印

private java.lang.String junereflect624.Cat.name

public int junereflect624.Cat.age

private java.lang.String junereflect624.Cat.color

private java.lang.String junereflect624.Cat.name

name

刘昭

21

 

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

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

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

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

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

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

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

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

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

 

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

步骤:

  1. 获取当前类
  2. 获取目标字段
  3. 获取包含泛型类型的类型 getGenericType()
  4. 强转至子类ParameterizedType   因为Type没有任何对应的方法
  5. 获得泛型真正的类型 getActualTypeArguments()

 
 
   
   
   
   
  1. import java.lang.reflect.Field;
  2. import java.lang.reflect.ParameterizedType;
  3. import java.lang.reflect.Type;
  4. import java.util.HashMap;
  5. import java.util.Map;
  6. public class GetGenericTypeDemo14 {
  7.    Map map = new HashMap();
  8.   
  9.    public static void main(String[] args) throws Exception {
  10.       Class c = GetGenericTypeDemo14.class;
  11.       Field f = c.getDeclaredField( "map");
  12.       System.out.println(f);
  13.       System.out.println(f.getName()); //map
  14.      
  15.       // Class getType()  返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。
  16.       Class cl = f.getType();
  17.       System.out.println( "获得其类型:"+cl);
  18. //获得其类型:interface java.util.Map
  19.     
  20.       /**
  21.        *  Type getGenericType() 返回一个 Type 对象,它表示此 Field 对象所表示字段的声明类型。
  22.        *  Type是Class的接口;
  23.        */
  24.       Type t = f.getGenericType(); //包含泛型的类型
  25.       System.out.println(t);
  26. //java.util.Map
  27.      
  28.       /**
  29.        * Type这个类里面没有任何的方法,所以需要调用子类的方法,那么大的类型转到小的类型,需要强转!
  30.        */
  31.       ParameterizedType pt = (ParameterizedType)t; //强转到其子类
  32.       /**
  33.        *  Type[] getActualTypeArguments()
  34.                    返回表示此类型实际类型参数的 Type对象的数组。
  35.           Type getOwnerType()
  36.                    返回 Type 对象,表示此类型是其成员之一的类型。
  37.           Type getRawType()
  38.                    返回 Type 对象,表示声明此类型的类或接口。
  39.        */
  40.      
  41.       t = pt.getRawType(); //类型的类或接口
  42.       System.out.println(t);
  43.      
  44.       Type[] ts = pt.getActualTypeArguments();
  45.       for (Type type : ts) {
  46.          System.out.println(type);
  47.          /**
  48.           *  class java.lang.String
  49.              class java.lang.Integer
  50.           */
  51.       }
  52.    }
  53. }

打印:

java.util.Map junereflect624.GetGenericTypeDemo14.map

map

获得其类型:interface java.util.Map

java.util.Map

interface java.util.Map

class java.lang.String

class java.lang.Integer

我的总结:多查找api,参考api中方法使用的限制,比如是否静态、返回值类型等。

你可能感兴趣的:(Java反射,反射通俗易懂)