【JVM】Java 反射原理及类加载过程

发布于:2025-07-29 ⋅ 阅读:(20) ⋅ 点赞:(0)

概述

  1. 定义
    1. 反射(Reflection):动态语言的关键,允许程序在运行期间借助 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
    2. 加载:将类的 .class 文件中的二进制数据读入内存,生成一个 java.lang.Class 对象
    3. 链接:验证类信息、为静态变量分配内存并设置默认值、解析符号引用为直接引用
    4. 初始化:执行静态变量赋值和静态代码块
    5. 动态代理:在运行时创建接口的实现类,通过代理类来调用目标对象的方法
  2. 功能
    1. 在程序运行期间拿到一个对象的所有信息
    2. 打破封装性,可以使用 private 类型的构造器、属性、方法

Class 加载过程

一、加载(Loading)

  1. 定义:将类的 .class 文件读入到内存,并为之创建一个 java.lang.Class 对象
  2. BootStrap ClassLoader
    1. C/C++ 编写,不能通过 Java 代码获取实例
    2. 功能:负责加载 Java 核心库(JAVA_HOME/jre/lib/rt.jar 或 sun.boot.class.path 路径下的内容)
  3. 继承于 ClassLoader 的类加载器
    1. Extension ClassLoader:jdk 提供,扩展类加载器
    2. Application ClassLoader:jdk 提供,系统类加载器,应用程序类加载器
    3. User ClassLoader:用户自定义类的加载器,实现应用的隔离、数据加密

二、链接(Linking)

  1. 定义:把类的二进制数据合并到 JRE 中
  2. 合并的三个阶段
    1. 验证(Verify):确保加载的类信息符合 JVM 规范(以 cafebebe 开头,没有安全问题)
    2. 准备(Prepare):正式为类变量(static)分配内存并设置类变量默认初始值,这些内存都在方法区中进行分配
    3. 解析(Parse):虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程

三、初始化(Initialization)

  1. 执行 “类构造器()方法” 的过程,负责收集类中所有类变量的赋值和静态代码块中的语句

常用对象

Class

  1. 定义

    1. 类的元数据,反射的源头,编译过程的产物,在运行过程中加载到内存
    2. 编译时产生:在 “.java” 源文件进行编译(javac.exe)时生成的 “.class” 字节码文件
    3. 运行时加载:在 “.class” 字节码文件进行加载( java.exe)时,会被加载到内存中,对应一个 Class 实例(只会加载一次)
  2. 获取方法

    // 1. 调用运行时类的静态属性 :class
    Class clazz = MyClass.class;
    
    // 2. 调用运行时类的对象的 getClass()
    MyClass myClass = new MyClass();
    Class clazz = myClass.getClass();
    
    // 3. 调用 Class 的静态方法 forName(String className)
    String className = "com.alec.package.MyClass";
    Class clazz = Class.forName(className);
    
    // 4. 使用类的加载器
    Class clazz = ClassLoader.getSystemClassLoader().loadClass("com.alec.package.MyClass")
    
  3. 常用方法

    返回类型 方法 功能
    Field Field getField(name) 根据字段名获取某个public的field(包括父类)
    Field getDeclaredField(name) 根据字段名获取当前类的某个field(不包括父类)
    Field[] getFields() 获取所有public的field(包括父类)
    Field[] getDeclaredFields() 获取当前类的所有field(不包括父类)
    Method Method getMethod(name, Class...) 获取某个publicMethod(包括父类),Class 是形参类型
    Method getDeclaredMethod(name, Class...) 获取当前类的某个Method(不包括父类),Class 是形参类型
    Method[] getMethods() 获取所有publicMethod(包括父类)
    Method[] getDeclaredMethods() 获取当前类的所有Method(不包括父类)
    Constructor getConstructor(Class...) 获取某个publicConstructor
    getDeclaredConstructor(Class...) 获取某个Constructor
    getConstructors() 获取所有publicConstructor
    getDeclaredConstructors() 获取所有Constructor
    继承 & 实现 Class getSuperclass()
    Class getInterfaces()
    Annotation Annotation getDeclaredAnnotaion(MyAnnotation.class) 获取类的 MyAnnotation 注解

Constructor

  1. 定义:构造器的元数据

  2. 常用方法

    方法 功能
    ClassInstance newInstance(…) 调用构造器方法,获取 Constructor 的实例对象,需要传入构造的形参
    void setAccessible(true) 使得 private 类型的构造器可以被调用

Field

  1. 定义:属性的元数据

  2. 常用方法

    方法 功能
    Annotation getDeclaredAnnotaion(MyField.class) 获取属性的 MyAnnotation 注解
    int getModifiers() 获取字段的修饰符,它是一个int,不同的 bit 表示不同的含义
    Class getType() 获取字段类型,也是一个Class实例,例如,String.class;
    String getName() 获取字段名称,例如,“name”
    set(myClassInstance, value) 设置 myClassInstance 实例的 field 属性为 value
    ElemType get(myClassInstance) 获取 myClassInstance 实例的 field 属性值
    void setAccessible(true) 使得 private 类型的属性可以被访问

Method

  1. 定义:方法的元数据

  2. 常用方法

    方法 功能
    int getModifiers() 获取方法的修饰符,它是一个int,不同的 bit 表示不同的含义
    Class getReturnType() 获取方法返回值类型,也是一个Class实例,例如:String.class
    String getName() 获取方法名称,例如:“getScore”
    Class[] getParameterTypes() 获取方法的参数类型,是一个Class数组,例如:{String.class, int.class}
    MethodReturnType invoke(…) 调用当前方法,需要传入形参
    void setAccessible(true) 使得 private 类型的方法可以被调用

    在这里插入图片描述


应用场景

  1. 框架开发中的应用
    1. Spring IOC:通过反射实现依赖注入,在运行时动态创建对象和管理依赖关系
    2. ORM框架(如MyBatis):利用反射将数据库记录映射到 Java 对象
    3. 单元测试框架(如JUnit):使用反射调用带有特定注解的测试方法
  2. 插件和模块化开发
    1. 动态加载外部 jar 包中的类
    2. 根据配置文件动态加载和实例化类
    3. 实现插件机制,支持功能扩展
  3. 通用功能实现
    1. 序列化和反序列化:JSON/XML解析器使用反射读取对象属性
    2. 对象拷贝:通过反射实现深拷贝
    3. 通用的数据验证和转换器

动态代理

  1. JDK 动态代理类:一个自定义类,需要实现 InvocationHandler 类
  2. 动态创建接口对象:定义了接口但不编写实现类,直接通过 JDK 提供的一个 Proxy.newProxyInstance() 创建一个 “接口对象”
  3. 功能
    1. 对目标对象的方法调用进行增强,不修改原有代码的情况下,实现对目标对象的功能扩展
    • 降低代码耦合度,提高系统可维护性
  4. 技术依赖关系:反射 -> 动态代理 -> AOP
  5. 示例:添加日志、事务、权限检查等功能

示例

  1. 目标:调用远程服务的接口,通过反射找到方法并传递参数进行方法调用

  2. 服务器代码

    @Slf4j
    @ChannelHandler.Sharable
    public class RpcRequestMessageHandler extends SimpleChannelInboundHandler<RpcRequestMessage> {
    
    		/**
    		* message 是客户端发送过来的请求消息
    		*/
        @Override
        protected void channelRead0(ChannelHandlerContext ctx, RpcRequestMessage message) {
            RpcResponseMessage response = new RpcResponseMessage();
            response.setSequenceId(message.getSequenceId());
            try {
    		        // 获取调用的服务
                HelloService service = (HelloService) ServicesFactory.getService(Class.forName(message.getInterfaceName()));
                // 获取调用的方法并通过invoke方法执行目标方法,并返回结果
                Method method = service.getClass().getMethod(message.getMethodName(), message.getParameterTypes());
                Object invokeResult = method.invoke(service, message.getParameterValue());
                response.setReturnValue(invokeResult);
            } catch (Exception e) {
                e.printStackTrace();
                String msg = e.getCause().getMessage();
                response.setExceptionValue(new Exception("远程调用出错:" + msg));
            }
            ctx.writeAndFlush(response);
        }
    
    }
    
  3. 客户端代码

    @Slf4j
    public class RpcClient {
        public static void main(String[] args) {
            NioEventLoopGroup group = new NioEventLoopGroup();
            LoggingHandler LOGGING_HANDLER = new LoggingHandler(LogLevel.DEBUG);
            MessageCodecSharable MESSAGE_CODEC = new MessageCodecSharable();
            RpcResponseMessageHandler RPC_HANDLER = new RpcResponseMessageHandler();
            try {
                Bootstrap bootstrap = new Bootstrap();
                bootstrap.channel(NioSocketChannel.class);
                bootstrap.group(group);
                bootstrap.handler(new ChannelInitializer<SocketChannel>() {
                    @Override
                    protected void initChannel(SocketChannel ch) throws Exception {
                        ch.pipeline().addLast(new ProcotolFrameDecoder());
                        ch.pipeline().addLast(LOGGING_HANDLER);
                        ch.pipeline().addLast(MESSAGE_CODEC);
                        ch.pipeline().addLast(RPC_HANDLER);
                    }
                });
                Channel channel = bootstrap.connect("localhost", 8080).sync().channel();
    
    						// 发送远程调用请求,请求中包含:序列号、接口名、方法名、返回值类型、请求参数类型、请求参数值
                ChannelFuture future = channel.writeAndFlush(new RpcRequestMessage(
                        1,
                        "cn.itcast.server.service.HelloService",
                        "sayHello",
                        String.class,
                        new Class[]{String.class},
                        new Object[]{"张三"}
                )).addListener(promise -> {
                    if (!promise.isSuccess()) {
                        Throwable cause = promise.cause();
                        log.error("error", cause);
                    }
                });
    
                channel.closeFuture().sync();
            } catch (Exception e) {
                log.error("client error", e);
            } finally {
                group.shutdownGracefully();
            }
        }
    }
    
    

网站公告

今日签到

点亮在社区的每一天
去签到