当前位置:首页 > 后端开发 > Java反射之获取类的信息

Java反射之获取类的信息

7个月前 (05-26)49

0. 前言

反射技术是Java的一大特色,它可以让Java程序运行过程中,获得一个类的所有字段和方法,也可以创建一个类的实例并调用任意一个方法。简而言之,就是解剖一个类,获得它的心肝脾肺肾,再进行操作。反射技术主要应用在框架的编写上,可能以后我们要做一个框架或者工具就会使用到反射技术。反射技术经常有用到的操作便是获取一个类的构造方法、字段、方法还有一些其它信息,并初始化一个类的对象并调用其方法。下面我就介绍一下反射技术的基本操作。

1. 获取Class对象

要想解剖一个类,得先获得它,一个类是用类Class描述的,所以一个类就是一个Class对象,下面有三种方法可以获取一个类的Class对象。此处获取Person类的Class对象,假设Person的全限定类名为edu.jyu.reflect.Person。

  1. Class类的forName()静态方法,Class clazz = Class.forName(“edu.jyu.reflect.Person”);
  2. 调用某个类的class属性,Class clazz = Person.class;
  3. 调用每个类的实例对象的getClass()方法,Class clazz = new Person().getClass();

2. 获取构造函数

类的构造方法,是用java.lang.reflect包中的类Constructor表示的,获取一个类的构造函数,有以下几个方法

  1. Constructor[] getDeclaredConstructors();返回已加载类声明的所有的构造方法(包括private修饰)的Constructor 对象数组.
  2. Constructor getDeclaredConstructor(Class[] paramTypes);返回已加载类声明的指定构造方法的Constructor 对象,paramTypes指定了参数类型.
  3. Constructor[] getConstructors();返回已加载类声明的所有的 public类型的构
    造方法的Constructor 对象数组.
  4. Constructor getConstructor(Class[] paramTypes);返回已加载类声明的指定
    的public类型的构造方法的Constructor对象,paramTypes指定了参数类型

这四个方法可以分成两类,一类(1、2方法)是可以获得private修饰的构造方法,一类(3、4方法)不可以,只能获取public的。而这两类中又可以分成两类,一类(方法名最后带s的,1、3方法)是获得所有可以获得的构造方法,一类(2、4)是获得指定参数列表对应的构造方法。说到这里可能会有点晕,通过下面这些代码大家可以看的更清晰。

先写一个Person类作为小白鼠,提供3个构造方法,其中有两个是public一个是private的,又有两个是带参数。

package edu.jyu.reflect;

class Person{
    public Person(){}

    public Person(Integer age){}

    private Person(String name){}
}

下面就是测试类,大家要对应着上面的Person类观察一下,这样比较清晰地看出各个方法之间的区别。

package edu.jyu.reflect;

import java.lang.reflect.Constructor;

class ReflectConstructorDemo{
    public static void main(String[] args) throws Exception{
        //获取Person类的Class对象
        Class pClazz = Class.forName("edu.jyu.reflect.Person");

        //=======可以获得private修饰的构造方法=========
        Constructor[] arrA = pClazz.getDeclaredConstructors();
        Constructor  conA1 = pClazz.getDeclaredConstructor(Integer.class);
        Constructor  conA2 = pClazz.getDeclaredConstructor(String.class);
        System.out.println("结果一:arrA length:"+arrA.length);
        System.out.println("结果二:"+conA1);
        System.out.println("结果三:"+conA2);

        //=======不能获得private修饰的构造方法=========
        Constructor[] arrB = pClazz.getConstructors();
        Constructor  conB1 = pClazz.getConstructor(Integer.class);
        //Constructor  conB2 = pClazz.getConstructor(String.class);
        System.out.println("结果四:arrB length:"+arrB.length);
        for (Constructor constructor : arrB) {
            System.out.println(constructor);
        }
        System.out.println("结果五:"+conB1);

    }

}

上面代码输出的结果

结果一:arrA length:3
结果二:public edu.jyu.reflect.Person(java.lang.Integer)
结果三:private edu.jyu.reflect.Person(java.lang.String)
结果四:arrB length:2
public edu.jyu.reflect.Person()
public edu.jyu.reflect.Person(java.lang.Integer)
结果五:public edu.jyu.reflect.Person(java.lang.Integer)

结果分析:

  1. 第一个结果可以看出arrA的长度为3,可以看出getDeclaredConstructors方法可以获取一个类所有的构造方法。
  2. 第二个结果是Person类的带有Integer参数的公有构造方法,说明getDeclaredConstructor方法可以获取一个类指定参数列表的公有构造方法。
  3. 第三个结果是Person类的带有String参数的私有构造方法,说明getDeclaredConstructor方法可以获取一个类指定参数列表的私有构造方法。
  4. 第四个结果说明getConstructors方法只能获取一个类所有的public修饰的构造函数。
  5. 第五个结果说明getConstructor方法可以获取一个类指定参数列表的公有构造方法。那么问题来了,怎么知道这个方法不能获取私有构造方法呢?把上面的Constructor conB2 = pClazz.getConstructor(String.class);这行代码的注释去掉,程序就会抛一个NoSuchMethodException异常,说明getConstructor根本就不能获得私有的构造方法。

3. 获取字段

类的字段,是用java.lang.reflect包中的类Field表示的,获取一个类的字段,有以下几个方法

  1. Field[] getDeclaredFields():返回已加载类声明的所有字段的Field对象数
    组,不包括从父类继承的字段.
  2. Field getDeclaredField(String name):返回已加载类声明的所有字段的
    Field对象,不包括从父类继承的字段,参数name指定字段的名称.
  3. Field[] getFields():返回已加载类声明的所有public型的字段的Field对象
    数组,包括从父类继承的字段
  4. Field getField(String name):返回已加载类声明的所有字段的 Field对象,
    包括从父类继承的字段,参数name指定字段的名称

这四个方法可以分成两类,一类(1、2方法)是可以获得private修饰的字段但是不包括从父类继承的字段,一类(3、4方法)不可以获得private修饰的字段但是包括从父类继承的字段。而这两类中又可以分成两类,一类(方法名最后带s的,1、3方法)是获得所有可以获得的字段,一类(2、4)是获得指定字段名称的字段。通过下面这些代码测试一下。

先写两个类,一个是Employee,一个是Manager,其中Manager继承Employee,这两个类都有一个公有字段和一个私有字段。

Employee类

package edu.jyu.reflect;

public class Employee {
    private String name;
    public Double salary;
}

Manager类

package edu.jyu.reflect;

public class Manager extends Employee{
     
    private Double bonus;
    public String Department;
}

下面是测试类

package edu.jyu.reflect;

import java.lang.reflect.Field;

public class ReflectFieldDemo {
    public static void main(String[] args) throws Exception{
        Class mClazz = Class.forName("edu.jyu.reflect.Manager");
        System.out.println("====getDeclaredFields结果====");
        Field[] arrA = mClazz.getDeclaredFields();
        for (Field field : arrA) {
            System.out.println(field);
        }
        System.out.println("====getDeclaredFields结果====");
        Field field = mClazz.getDeclaredField("bonus");
        System.out.println(field);
        field = mClazz.getDeclaredField("Department");
        System.out.println(field);
        //field = mClazz.getDeclaredField("name");

        System.out.println("====getFields结果====");
        Field[] arrB = mClazz.getFields();
        for (Field field2 : arrB) {
            System.out.println(field2);
        }
        System.out.println("====getFields结果====");
        field = mClazz.getField("Department");
        System.out.println(field);
        field = mClazz.getField("salary");
        System.out.println(field);
        //field = mClazz.getField("bonus");
    }
}

输出结果

====getDeclaredFields结果====
private java.lang.Double edu.jyu.reflect.Manager.bonus
public java.lang.String edu.jyu.reflect.Manager.Department
====getDeclaredFields结果====
private java.lang.Double edu.jyu.reflect.Manager.bonus
public java.lang.String edu.jyu.reflect.Manager.Department
====getFields结果====
public java.lang.String edu.jyu.reflect.Manager.Department
public java.lang.Double edu.jyu.reflect.Employee.salary
====getFields结果====
public java.lang.String edu.jyu.reflect.Manager.Department
public java.lang.Double edu.jyu.reflect.Employee.salary

其中那两句被注释的代码如果去掉注释,将会抛出NoSuchFieldException异常。

4. 获取方法

类的方法,是用java.lang.reflect包中的类Method表示的,获取一个类的方法,有以下几个方法

  1. Method[] getDeclaredMethods():返回已加载类声明的所有方法的 Method 对象数组,不包括从父类继承的方法.
  2. Method getDeclaredMethod(String name,Class[] paramTypes):返回已加载类声明的所有方法的 Method对象,不包括从父类继承的方法,参数name指定方
    法的名称,参数 paramTypes指定方法的参数类型.
  3. Method[] getMethods():返回已加载类声明的所有方法的Method对象数组,包
    括从父类继承的方法.
  4. Method getMethod(String name,Class[] paramTypes):返回已加载类声明的
    所有方法的Method对象,包括从父类继承的方法,参数name指定方法的名称,参
    数paramTypes指定方法的参数类型

大家可以观察到,获取类方法的这几个方法与获取类的字段十分相像,所以在此便不再多解释了。

5. 获取其它信息

当你得到一个类的Class对象的时候,基本上你就可以获取它的全部信息了,除了构造方法,字段,方法外还有一些类的包名、父类等等信息,如下面这几种。

  1. int getModifiers():返回已加载类的修饰符的整形标识值.
  2. Package getPackage():返回已加载类的包名
  3. Class getSuperclass():返回已加载类的父类的 Class实例.
  4. Class [] getInterfaces():返回已加载类实现的接口的 Class对象数组.
  5. boolean isInterface():返回已加载类是否是接口

还有更多的反射方法大家可以去查看API


如果上面的内容有错误的地方或者讲的不好的地方,还请大家指点一下,我好及时修改。

作者:腹黑大壁花
来源链接:https://blog.csdn.net/TimHeath/article/details/53305528

“Java反射之获取类的信息” 的相关文章

Java反射之构造方法反射

Java反射之构造方法反射

上一篇Java反射之Class类我们介绍了java反射的关键类Class, 反射就是由一个java类映射得到一个java类。 所以,我们自然能想到,...

Java反射-修改private final成员变量值

Java反射-修改private final成员变量值

大家都知道使用java反射可以在运行时动态改变对象的行为,甚至是private final的成员变量,但并不是所有情况下,都可以修改成员变量。今天就举几个小例子说明。 ...

java反射的基本实现

import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang....

Java反射一

Java反射一

一 .什么是反射? class是一切反射的根源,JAVA反射机制是在运行状态中,对于任和一个类,通过反射都能够知道...

java反射作用

java反射作用

详细内容 Java的反射机制是Java特性之一,反射机制是构建框架技术的基础所在。灵活掌握Java反射机制,对大家以后学习框架技术有很大的帮助。...

JAVA反射其实就是那么一回事

概念:什么是反射   java反射机制: JAVA反射机制是在运行状态中,           对于任意一个类,都能够知道这个类的所有属性和方法;           ...

【译】3. Java反射——构造函数

原文地址:http://tutorials.jenkov.com/java-reflection/constructors.html =======================...

java反射工具类

package com.yingchao.kgou.core; import java.lang.reflect.Field; import java.lang.reflec...

JAVA反射概念及使用详解(超详细)

JAVA反射概念及使用详解(超详细)

JAVA反射概念及使用详解 JAVA反射概念及使用详解 一、什么是反射? 反射:框架设计的灵魂 框架:半成品软件。可以在框架的基础上进行软件开发,简化...

利用java反射获取和设置属性值

/** * 根据属性名获取属性值 * * @param fieldName * @param object * @return */ private String...