[01] 反射的基本概念和常用类


1、什么是反射

在了解反射之前,我们都是如何使用一个Java类的?
  • 已知一个类的类名,以及类中的方法、属性和构造方法等
  • 调用构造方法创建对象
  • 使用对象调用方法或者属性

那么问题来了,如果我们只知道一个类的类名,能否动态得到类的信息,包括其方法和属性?
  • 通过反射

所以反射的概念是:在运行状态中,对任意类都可知道其所有属性和方法,对任意对象都可调用其方法和属性。这种动态获取信息以及动态调用对象方法的功能,称之为Java的反射机制。

如Spring框架只需要通过xml文件描述类的基本信息,就可以利用反射机制动态装配对象。

2、反射的相关类

和反射相关的类主要包括 Class、Constructor、Method、Field等,除了Class,其他的类都位于java.lang.reflect包中。其中最重要的类是Class,可以说,反射的使用都是从Class开始的。

2.1 Class类

2.1.1 Class实例的获取
把一个类封装成为Class类,Class实例主要有三种方式获取:
  • //使用对象名获取
  • String str = "hello";
  • Class clazz = str.getClass();

  • //使用类名获取,在类名加后缀 .class
  • Class clazz = String.class;

  • //使用类名获取,通过Class的静态方法forName()
  • Class clazz = Class.forName("java.lang.String");

2.1.2 Class类的主要方法
Class类中的主要方法有:
  • getMethod:返回类中某个方法的实例
  • getMethods:返回类中所有方法的实例
  • getField:返回类中某个属性的实例
  • getFields:返回类中所有属性的实例
  • getConstructor:返回类中的一个构造方法的实例
  • getXXX:Class中还有若干get方法,获取类的基本信息

需要注意的是,以上涉及的获取Method或Field实例的方法,实际上还有一个类似的方法,不过名字中多个词Declared,如getDeclaredMethods(),区别在于:
  • 包含Declared:它仅获取自身类声明的方法,包括公开的、私有的、保护的等
  • 没有Delcared的普通get方法:会获取某个类所有的公开(public)成员,包括自己定义的和继承下来的

简单示例:
public static void main(String[] args) { 
    Class clazz_str = String.class;
    Method[] methods = clazz_str.getMethods();
    for (Method method : methods) {
        System.out.println(method.getName());
    }
}

2.2 Constructor类

2.2.1 实例的获取
Constructor类的对象是由Class对象获取,Class类中定义了如下方法:
  • Constructor<T> getConstructor(Class... parameterTypes):通过指定参数类型,返回构造方法实例
  • Constructor[] getConstructors():返回该类的所有构造方法实例

这里所说的指定的参数类型,是指实际构造方法的形参。比如有构造方法 public Student(String name),那么需要:
Class stuClazz = Student.class;
Constructor stuCon = stuClazz.getConstructor(String.class);

2.2.2 实例的基本信息获取
该类可以通过getXXX的方法,获取构造方法的基本信息,如:
  • getName:返回构造方法的名字
  • getParameterTypes:返回构造方法的参数类型

2.2.3 创建对象
除了构造方法的基本信息,也可以通过该Constructor的实例创建对象:
  • newInstance(Object... initargs);

示例:
Class stuClazz = Student.class;
Constructor stuCon = stuClazz.getConstructor(String.class);
Student stu = (Student)stuCon.newInstance("zhangsan");

2.3 Method类

2.3.1 Method的获取
Method类的实例由Class对象获取:
  • Method getMethod(String name, Class... parameterTypes):通过指定方法名,参数类型,返回Method实例
  • Method[] getMethods():返回该类中所有方法的Method实例

2.3.2 Method获取基本信息
Method封装了类中的方法,可以动态获取方法的信息,如:
  • getReturnType:获取方法的返回值类型
  • getName:获得方法名
  • getParameterTypes:获得方法参数类型

2.3.3 Method动态调用方法
除了动态获得方法信息,Method类还可以动态调用某个对象的具体方法:
  • invoke(Object obj, Object... args);

示例:
public static void main(String[] args) throws Exception {
    Class stuClazz = Student.class;
    Constructor stuCon = stuClazz.getConstructor(String.class);
    Student student = (Student)stuCon.newInstance("zhangsan");

    Method study = stuClazz.getMethod("study");
    study.invoke(student);

    Method studyWithOne = stuClazz.getMethod("studyWithOne", String.class);
    studyWithOne.invoke(student, "lisi");
}

2.4 Field类

2.4.1 Field的获取
获得Field实例,都是通过Class中的方法实现的:
  • public Field getField(String name)  
  • 通过指定Field的名字,返回Field实例
  • 注意Field的访问权限

之前提到过,如果单纯地使用getField那么获取到的方法实例都是public的,如果要获取private方法,需要使用诸如getDeclaredField方法:
//如有Student类,有private权限的属性name
Class stuClazz = Student.class;
Field name = stuClazz.getField("name"); // NG,报异常,找不到该方法
Field name = stuClazz.getDeclaredField("name"); // OK

备注:
Java Field.get()取得对象的Field属性值,即field.get(Class clazz)可以获取对象属性的值,类似于调用无限制的getter方法

3、反射的重要说明

反射实际上将所有的类成分映射成为对应的的Class对象,这里的Class对象其实可以堪称是一种类型。并不知只有类才能转换成Class对象。

也即是说,如果真的需要(比如某些方法中要求参数是Class类型),像基本的数据类型(boolean、byte、char、short、int、long、float、double)甚至关键字如 void 也可以表示为Class对象(形如 int.class)

比如某些方法,如果你要用反射表示,可能参数可能会写成如 (String.class, int.class) 这种形式,这是sun公司定义的规则,不需要深刻去理解为什么。

例如 getConstructor(Class<?>... parameterTypes):
Class stuClazz = Student.class;
Constructor stuCon = stuClazz.getConstructor(String.class);

原文地址:https://www.cnblogs.com/deng-cc/p/7462557.html