概述
- 定义
- 反射(Reflection):动态语言的关键,允许程序在运行期间借助 Reflection API 取得任何类的内部信息,并能直接操作任意对象的内部属性及方法
- 加载:将类的 .class 文件中的二进制数据读入内存,生成一个 java.lang.Class 对象
- 链接:验证类信息、为静态变量分配内存并设置默认值、解析符号引用为直接引用
- 初始化:执行静态变量赋值和静态代码块
- 动态代理:在运行时创建接口的实现类,通过代理类来调用目标对象的方法
- 功能
- 在程序运行期间拿到一个对象的所有信息
- 打破封装性,可以使用 private 类型的构造器、属性、方法
Class 加载过程
一、加载(Loading)
- 定义:将类的 .class 文件读入到内存,并为之创建一个 java.lang.Class 对象
- BootStrap ClassLoader
- C/C++ 编写,不能通过 Java 代码获取实例
- 功能:负责加载 Java 核心库(JAVA_HOME/jre/lib/rt.jar 或 sun.boot.class.path 路径下的内容)
- 继承于 ClassLoader 的类加载器
- Extension ClassLoader:jdk 提供,扩展类加载器
- Application ClassLoader:jdk 提供,系统类加载器,应用程序类加载器
- User ClassLoader:用户自定义类的加载器,实现应用的隔离、数据加密
二、链接(Linking)
- 定义:把类的二进制数据合并到 JRE 中
- 合并的三个阶段
- 验证(Verify):确保加载的类信息符合 JVM 规范(以 cafebebe 开头,没有安全问题)
- 准备(Prepare):正式为类变量(static)分配内存并设置类变量默认初始值,这些内存都在方法区中进行分配
- 解析(Parse):虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程
三、初始化(Initialization)
- 执行 “类构造器()方法” 的过程,负责收集类中所有类变量的赋值和静态代码块中的语句
常用对象
Class
定义
- 类的元数据,反射的源头,编译过程的产物,在运行过程中加载到内存
- 编译时产生:在 “.java” 源文件进行编译(javac.exe)时生成的 “.class” 字节码文件
- 运行时加载:在 “.class” 字节码文件进行加载( java.exe)时,会被加载到内存中,对应一个 Class 实例(只会加载一次)
获取方法
// 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")
常用方法
返回类型 方法 功能 Field Field getField(name)
根据字段名获取某个public的field(包括父类) Field getDeclaredField(name)
根据字段名获取当前类的某个field(不包括父类) Field[] getFields()
获取所有public的field(包括父类) Field[] getDeclaredFields()
获取当前类的所有field(不包括父类) Method Method getMethod(name, Class...)
获取某个 public
的Method
(包括父类),Class 是形参类型Method getDeclaredMethod(name, Class...)
获取当前类的某个 Method
(不包括父类),Class 是形参类型Method[] getMethods()
获取所有 public
的Method
(包括父类)Method[] getDeclaredMethods()
获取当前类的所有 Method
(不包括父类)Constructor getConstructor(Class...)
获取某个 public
的Constructo
rgetDeclaredConstructor(Class...)
获取某个 Constructor
getConstructors()
获取所有 public
的Constructor
getDeclaredConstructors()
获取所有 Constructor
继承 & 实现 Class getSuperclass()
Class getInterfaces()
Annotation Annotation getDeclaredAnnotaion(MyAnnotation.class)
获取类的 MyAnnotation 注解
Constructor
定义:构造器的元数据
常用方法
方法 功能 ClassInstance newInstance(…)
调用构造器方法,获取 Constructor 的实例对象,需要传入构造的形参 void setAccessible(true)
使得 private 类型的构造器可以被调用
Field
定义:属性的元数据
常用方法
方法 功能 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
定义:方法的元数据
常用方法
方法 功能 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 类型的方法可以被调用
应用场景
- 框架开发中的应用
- Spring IOC:通过反射实现依赖注入,在运行时动态创建对象和管理依赖关系
- ORM框架(如MyBatis):利用反射将数据库记录映射到 Java 对象
- 单元测试框架(如JUnit):使用反射调用带有特定注解的测试方法
- 插件和模块化开发
- 动态加载外部 jar 包中的类
- 根据配置文件动态加载和实例化类
- 实现插件机制,支持功能扩展
- 通用功能实现
- 序列化和反序列化:JSON/XML解析器使用反射读取对象属性
- 对象拷贝:通过反射实现深拷贝
- 通用的数据验证和转换器
动态代理
- JDK 动态代理类:一个自定义类,需要实现 InvocationHandler 类
- 动态创建接口对象:定义了接口但不编写实现类,直接通过 JDK 提供的一个
Proxy.newProxyInstance()
创建一个 “接口对象” - 功能
- 对目标对象的方法调用进行增强,不修改原有代码的情况下,实现对目标对象的功能扩展
- 降低代码耦合度,提高系统可维护性
- 技术依赖关系:反射 -> 动态代理 -> AOP
- 示例:添加日志、事务、权限检查等功能
示例
目标:调用远程服务的接口,通过反射找到方法并传递参数进行方法调用
服务器代码
@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); } }
客户端代码
@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(); } } }