Java 基础知识之 Java 反射
发布日期:2021-06-29 12:02:50 浏览次数:2 分类:技术文章

本文共 12044 字,大约阅读时间需要 40 分钟。

什么是Java反射?

Java 反射机制是 Java 自诞生以来就具备的能力,用于在 Java 程序运行过程中动态的获取类的信息,调用类中的方法。

Java 反射的使用场景

  • 获取类的信息:如 Spring 中通过读取类的注解信息注册 Bean 对象。
  • 调用类的方法:Spring 可以读取 XML 的配置信息,选择恰当的构造器,通过反射实例化 Bean 对象。

Java 反射机制提供了哪些 API ?

Java 虚拟机将字节码加载到内存中,并且抽象出了一些 Java 类。当程序运行时,可以通过这些类获取字节码中类的元信息。

Java反射的包名为java.lang.reflect,主要的 UML 类图如下。

Java 反射类
反射相关的类主要如下:

  • Class:表示Java类。
  • Field:表示Java类中的成员变量。
  • Method:表示Java类中的成员方法。
  • Constructor:表示Java类的构造方法。

其他类如下:

  • Array:表示数组。
  • AnnotatedElement:JDK 1.5 新增,泛型相关,表示可以被注解标注的元素,如类、成员变量、
    方法等。
  • Member:表示 Java 类中的成员,如成员变量,成员方法,构造方法。
  • AccessibleObject:JDK 1.2 新增,Field、Method、Constructor的父接口,提供对反射对象抑制默认的 Java 访问控制检查的能力。
  • GenericDeclaration:JDK 1.5 新增,泛型相关,表示可以定义类型变量的元素。
  • Type:JDK 1.5 新增,表示 Java 中的某一种类型。
  • Parameter:JDK 1.8 新增,表示成员方法或构造方法中的某一个参数。
  • AnnotatedType:JDK 1.8 新增,表示可以被注解标注的类型。
  • Executable:JDK 8 新增,Method 和 Constructor 的父接口。
  • TypeVariable:JDK 1.5 新增,泛型相关,类型变量,如List 中的 T。
  • GenericArrayType:JDK 1.5 新增,泛型相关,泛型数组类型,如 T[] 。
  • ParameterizedType:JDK 1.5 新增,泛型相关,参数化类型,如 Class 。
  • WildcardType:JDK 1.5 新增,泛型相关,通配符类型,如 Class<? extend Number> 中的 ? extend Number

Class 类

Class 类表示 Java 中的某一个类,不包含类的泛型信息。

获取方式主要有三种,如下:

  • java.lang.Class#forName(java.lang.String):如 Class<?> cls = Class.forName("com.mysql.cj.jdbc.Driver")
  • java.lang.Object#getClass:如 Class<?> cls = "hello,java".getClass()
  • Type.class:如 Class<?> cls = String.class

Class 类中常用的方法如下:

类定义相关方法

方法 用途
public static Class<?> forName(String className) 根据类名称获取Class对象
public static Class<?> forName(String name, boolean initialize,ClassLoader loader) 根据类名称获取Class对象
public Package getPackage() 获取类的包信息
public native int getModifiers() 获取类的修饰符
public native Class<? super T> getSuperclass() 获取当前类的父类
public Type getGenericSuperclass() 获取泛型父类型
public AnnotatedType getAnnotatedSuperclass() 获取表示当前类的父类的AnnotatedType对象
public String getSimpleName() 获取表示当前类的简单名称
public Class<?>[] getInterfaces() 获取接口数组
public Type[] getGenericInterfaces() 获取泛型接口数组
public AnnotatedType[] getAnnotatedInterfaces() 获取表示当前类的接口的AnnotatedType数组
public Class<?>[] getClasses() 获取当前类和其父类公有内部类数组
public Class<?> getDeclaringClass() throws SecurityException 获取定义当前内部类的外部类,如果当前内部类是匿名内部类返回null
public XXX<?> getEnclosingXXX() throws SecurityException 获取当前匿名内部类所在的类/构造方法/成员方法,XXX 表示 Class/Constructor/Method

类成员相关方法

类成员包括内部类、构造方法(Constructor)、成员变量(Field)和成员方法(Method)。

下表中的 XXX 可以表示 Field、Constructor 或者 Method。

方法 用途
public XXX getDeclaredXXX(…) 获取当前类定义中给定参数指定的成员变量/构造方法/成员方法
public XXX[] getDeclaredXXXs() throws SecurityException 获取当前类定义的所有内部类(Class)/成员变量/构造方法/成员方法
public XXX getXXX(…) 获取当前类及其父类中给定参数的共有成员变量/构造方法/成员方法 (构造方法只获取当前类中定义的)
public XXX[] getXXXs() throws SecurityException 获取当前类及其父类中所有共有内部类(Class)/成员变量/构造方法/成员方法 (构造方法只获取当前类中定义的)

其他方法

方法 用途
public boolean isAnnotation() 当前类是否为注解
public boolean isAnonymousClass() 当前类是否为匿名内部类
public native boolean isArray() 当前类是否为数组
public native boolean isAssignableFrom(Class<?> cls) 当前类是否为给定类的父类
public boolean isEnum() 当前类是否表示枚举类
public native boolean isInstance(Object obj) 当前类是否为给定对象的类型
public native boolean isInterface() 当前类是否表示接口
public boolean isLocalClass() 当前类是否为局部内部类
public boolean isMemberClass() 当前类是否为成员内部类
public native boolean isPrimitive() 当前类是否表示基本数据类型
public boolean isSynthetic() 当前类是否为编译期自动生成的类
public native Class<?> getComponentType() 获取当前数组类的元素类型
public T[] getEnumConstants() 获取当前枚举类的对象数组
public Class<? extends U> asSubclass(Class clazz) 将当前Class对象转换为指定Class对象的子类
public T cast(Object obj) 将给定对象转换为当前Class对象表示的类或接口
public T newInstance() 使用当前类的无参构造方法实例化对象
public ClassLoader getClassLoader() 获取当前类的类加载器
public String getName() 获取类的名称
public String getCanonicalName() 获取 Java 语言规范定义的底层类的名称
public String toGenericString() 获取当前类的字符串描述信息

Field 类

Field 通过 Class 的 getDeclaredField(…)、getDeclaredFields()、getField(…) 或者 getFields() 方法获取,主要提供了设置和获取成员变量值的方法。

具体如下,其中XXX可以表示 Boolean、Byte、Char、Short、Int、Long、Float、Double。

方法 用途
public xXX getXXX(Object obj) throws IllegalArgumentException, IllegalAccessException 获取当前成员变量表示的 Java 基本类型的值
public Object get(Object obj) throws IllegalArgumentException, IllegalAccessException 获取当前成员变量表示的值
public void setXxx(Object obj, xxx b) throws IllegalArgumentException, IllegalAccessException 将当前成员变量设置为给定的 Java 基本类型的值
public void set(Object obj, Object value) throws IllegalArgumentException, IllegalAccessException 将当前成员变量设置为给定的值

Constructor 类

Constructor 表示构造方法,主要提供了实例化 Java 对象的方法,具体如下。

方法 用途
public T newInstance(Object … initargs) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException 实例化 Java 对象

Method 类

Method 表示 Java 中的方法,经常用来调用方法,主要的方法如下。

方法 用途
public Object getDefaultValue() 获取注解中属性的默认值
public Type getGenericReturnType() 获取方法返回泛型类型
public Class<?> getReturnType() 获取方法返回类型
public Object invoke(Object obj, Object… args) 调用方法
public boolean isBridge() 方法是否为桥接方法
public boolean isDefault() 方法是否为默认方法

反射使用示例

示例1,打印给定类的结构

代码如下:

package com.zzuhkp;import java.lang.annotation.Annotation;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.lang.reflect.Type;import java.util.Arrays;import java.util.stream.Collectors;import javax.validation.constraints.NotBlank;import javax.validation.constraints.NotNull;/** * @author zzuhkp * @date 2020-08-05 9:48 * @since 1.0 */public class ReflectTest {
@NotBlank(message = "名称不能为空") private String name; public static void main(String[] args) {
printClass(ReflectTest.class); } @Deprecated public static void printClass(@NotNull Class
cls) {
StringBuilder sb = new StringBuilder(); // 获取包信息 Package aPackage = cls.getPackage(); if (aPackage != null) {
sb.append("package ").append(aPackage.getName()).append(";\n\n"); } // 获取类修饰符信息 String modifier = Modifier.toString(cls.getModifiers()); if (modifier.length() > 0) {
sb.append(modifier).append(" "); } // 获取类名 sb.append("class ").append(cls.getSimpleName()).append(" "); // 获取父类 Type superclass = cls.getGenericSuperclass(); if (superclass != Object.class) {
sb.append("extend ").append(superclass.getTypeName()).append(" "); } // 获取接口 Type[] interfaces = cls.getGenericInterfaces(); if (interfaces.length > 0) {
String interfaceStr = Arrays.stream(interfaces).map(Type::getTypeName).collect(Collectors.joining(",")); sb.append("implements ").append(interfaceStr).append(" "); } sb.append("{\n\n"); // 获取成员变量 Field[] fields = cls.getDeclaredFields(); for (Field field : fields) {
//获取成员变量的注解 for (Annotation annotation : field.getAnnotations()) {
sb.append(" ").append(annotation).append("\n"); } // 获取成员变量修饰符 String fieldModifier = Modifier.toString(field.getModifiers()); // 获取成员变量类型名称 String fieldTypeName = field.getGenericType().getTypeName(); // 获取成员变量名称 String fieldName = field.getName(); sb.append(" ").append(fieldModifier).append(" ").append(fieldTypeName) .append(" ").append(fieldName).append(";\n"); } sb.append("\n"); Constructor
[] constructors = cls.getDeclaredConstructors(); for (Constructor
constructor : constructors) {
for (Annotation annotation : constructor.getAnnotations()) {
sb.append(" ").append(annotation).append("\n"); } sb.append(" "); // 获取构造方法修饰符 int constructorModifiers = constructor.getModifiers(); String methodModifier = Modifier.toString(constructorModifiers); if (methodModifier.length() > 0) {
sb.append(methodModifier).append(" "); } // 获取构造方法名称 String constructorName = constructor.getName(); sb.append(constructorName).append("("); // 获取方法参数 String parameters = Arrays.stream(constructor.getParameters()) .map(parameter -> {
// 获取方法参数注解 String str = Arrays.stream(parameter.getAnnotations()).map(Annotation::toString) .collect(Collectors.joining(" ")); if (str.length() > 0) {
str = str + " "; } // 获取方法参数类型及名称 str = str + parameter.getParameterizedType().getTypeName() + " " + parameter.getName(); return str; }) .collect(Collectors.joining(",")); sb.append(parameters); sb.append(")"); if (!Modifier.isNative(constructorModifiers)) {
sb.append("{\n").append(" ..\n").append(" }"); } else {
sb.append(";"); } sb.append("\n"); } // 获取成员方法 Method[] methods = cls.getDeclaredMethods(); for (Method method : methods) {
for (Annotation annotation : method.getAnnotations()) {
sb.append(" ").append(annotation).append("\n"); } sb.append(" "); // 获取成员方法修饰符 int methodModifiers = method.getModifiers(); String methodModifier = Modifier.toString(methodModifiers); if (methodModifier.length() > 0) {
sb.append(methodModifier).append(" "); } // 获取成员方法返回值类型 String returnType = method.getGenericReturnType().getTypeName(); sb.append(returnType).append(" "); // 获取成员方法名称 String methodName = method.getName(); sb.append(methodName).append("("); // 获取方法参数 String parameters = Arrays.stream(method.getParameters()) .map(parameter -> {
// 获取方法参数注解 String str = Arrays.stream(parameter.getAnnotations()).map(Annotation::toString) .collect(Collectors.joining(" ")); if (str.length() > 0) {
str = str + " "; } // 获取方法参数类型及名称 str = str + parameter.getParameterizedType().getTypeName() + " " + parameter.getName(); return str; }) .collect(Collectors.joining(",")); sb.append(parameters); sb.append(")"); if (!Modifier.isNative(methodModifiers)) {
sb.append("{\n").append(" ..\n").append(" }"); } else {
sb.append(";"); } sb.append("\n"); } sb.append("}"); System.out.println(sb); }}

执行结果如下:

package com.zzuhkp;public class ReflectTest {
@javax.validation.constraints.NotBlank(message=名称不能为空, groups=[], payload=[]) private java.lang.String name; public com.zzuhkp.ReflectTest(){
.. } public static void main(java.lang.String[] args){
.. } private static java.lang.String lambda$printClass$1(java.lang.reflect.Parameter parameter){
.. } @java.lang.Deprecated() public static void printClass(@javax.validation.constraints.NotNull(message={
javax.validation.constraints.NotNull.message}, groups=[], payload=[]) java.lang.Class
cls){
.. } private static java.lang.String lambda$printClass$0(java.lang.reflect.Parameter parameter){
.. }}

示例2,通过反射调用方法

代码如下:

public class ReflectTest {
static class Test {
private void sayHello() {
System.out.println("你好,Java"); } } public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Test test = new Test(); Method method = Test.class.getDeclaredMethod("sayHello"); method.setAccessible(true); method.invoke(test); }}

执行结果如下:

你好,Java

可以看到,私有的方法也可以通过反射进行调用。

转载地址:https://blog.csdn.net/zzuhkp/article/details/107744185 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:重识 Java 注解
下一篇:Java Bean Validation 详解

发表评论

最新留言

路过按个爪印,很不错,赞一个!
[***.219.124.196]2024年04月22日 10时16分33秒