Java 基础知识之 Java 反射

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

什么是Java反射?

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


Java 反射的使用场景

获取类的信息:如 Spring 中通过读取类的注解信息注册 Bean 对象。

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

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

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


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

image.png


反射相关的类主要如下:


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。


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 类中常用的方法如下:


类定义相关方法

image.png


类成员相关方法

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

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


image.png

其他方法

image.png


Field 类

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

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


image.png


Constructor 类

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


image.png

Method 类

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


image.png

反射使用示例

示例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


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

目录
相关文章
|
13天前
|
IDE Oracle Java
java基础教程(1)-Java概述和相关名词解释
【4月更文挑战第1天】Java是1995年Sun Microsystems发布的高级编程语言,以其跨平台特性著名。它介于编译型和解释型语言之间,通过JVM实现“一次编写,到处运行”。Java有SE、EE和ME三个版本,分别针对标准、企业及嵌入式应用。JVM是Java虚拟机,确保代码在不同平台无需重编译。JRE是运行环境,而JDK包含开发工具。要安装Java开发环境,可从Oracle官网下载JDK,设置JAVA_HOME环境变量并添加到PATH。
|
18天前
|
Java 程序员 调度
Java中的多线程编程:基础知识与实践
【4月更文挑战第5天】 在现代软件开发中,多线程编程是一个不可或缺的技术要素。它允许程序员编写能够并行处理多个任务的程序,从而充分利用多核处理器的计算能力,提高应用程序的性能。Java作为一种广泛使用的编程语言,提供了丰富的多线程编程支持。本文将介绍Java多线程编程的基础知识,并通过实例演示如何创建和管理线程,以及如何解决多线程环境中的常见问题。
|
4天前
|
监控 Java 开发者
掌握 Java 反射和动态代理
【4月更文挑战第19天】Java反射和动态代理提供强大功能和灵活性。反射允许运行时检查和操作类,获取类信息、动态调用方法,但可能带来性能损失和降低代码可读性。动态代理则用于创建代理对象,实现透明性和横切关注点分离,常用于日志、权限检查等。两者结合能实现更复杂功能。掌握这些技术能提升代码的灵活性和可扩展性,但也需注意性能和可读性。通过学习和实践,能更好地构建高效软件系统。
|
7天前
|
存储 Java
Java基础教程(7)-Java中的面向对象和类
【4月更文挑战第7天】Java是面向对象编程(OOP)语言,强调将事务抽象成对象。面向对象与面向过程的区别在于,前者通过对象间的交互解决问题,后者按步骤顺序执行。类是对象的模板,对象是类的实例。创建类使用`class`关键字,对象通过`new`运算符动态分配内存。方法包括构造函数和一般方法,构造函数用于对象初始化,一般方法处理逻辑。方法可以有0个或多个参数,可变参数用`类型...`定义。`this`关键字用于访问当前对象的属性。
|
8天前
|
Java 索引
Java基础教程(6)-Java中的流程控制语句
【4月更文挑战第6天】Java流程控制包括选择(if, switch)、重复(while, do-while, for)和跳转(break, continue, return)语句。选择语句根据条件执行不同路径,if和switch用于单条件和多条件分支。重复语句用于循环,如for循环的初始化、条件和迭代部分,以及while和do-while循环。跳转语句中,break用于立即退出循环,continue结束当前循环迭代,return则从方法中返回。此外,Java的for each循环简化了数组或集合的遍历,但不能控制遍历顺序或索引。
|
10天前
|
存储 Java 编译器
Java基础教程(4)-Java中的操作符
【4月更文挑战第4天】Java中的String是常用类,字符串是不可变对象,用双引号表示。String对象在编译期长度受限于65535,运行期不超过Int范围。字符串方法如length()、substring()、replace()、equals()等提供了多种操作。可变字符串可使用StringBuffer或StringBuilder。String对象通过字符串池优化内存,池中已有相同内容字符串则返回其引用。
|
11天前
|
Java
代码的魔法师:Java反射工厂模式详解
代码的魔法师:Java反射工厂模式详解
23 0
|
14天前
|
安全 Java
java反射篇
java反射篇
|
15天前
|
存储 Java
java反射——设计框架的灵魂
java反射——设计框架的灵魂
|
21天前
|
Java
Java通过反射获取类调用方法
Java通过反射获取类调用方法
18 0

热门文章

最新文章