Java基础概念
大约 3 分钟
Java中的动态代理、动态加载和JNI大白话解释
1. 动态代理:帮别人办事的中介
大白话解释:
动态代理就像你找了一个中介帮你办事。你不用自己亲自去做某些事情(比如租房、买票),而是让中介去帮你做。中介可以在帮你办事前后,还能做一些额外的事情(比如收中介费、记录日志等)。
特点:
- 运行时动态创建代理类
- 不需要为每个类手动编写代理
- 常用于AOP(面向切面编程)
代码示例:
import java.lang.reflect.*;
// 接口:租房
interface Rent {
void rentHouse();
}
// 真实对象:房东
class Landlord implements Rent {
public void rentHouse() {
System.out.println("房东出租房子");
}
}
// 代理调用处理器
class RentHandler implements InvocationHandler {
private Object target; // 被代理的对象
public RentHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("中介开始办事,先收中介费");
Object result = method.invoke(target, args); // 调用真实对象的方法
System.out.println("中介办事结束,记录日志");
return result;
}
}
public class DynamicProxyDemo {
public static void main(String[] args) {
// 真实对象
Landlord landlord = new Landlord();
// 创建代理对象
Rent proxy = (Rent) Proxy.newProxyInstance(
landlord.getClass().getClassLoader(),
landlord.getClass().getInterfaces(),
new RentHandler(landlord)
);
// 通过代理调用方法
proxy.rentHouse();
}
}
输出:
中介开始办事,先收中介费
房东出租房子
中介办事结束,记录日志
2. 动态加载:现用现学
大白话解释:
动态加载就像你上学时不用一次性把所有课本都背到学校,而是根据课程表,上什么课带什么书。Java程序也可以在运行时才加载需要的类,而不是启动时就加载所有类。
特点:
- 延迟加载,节省内存
- 可以实现插件化架构
- 通过ClassLoader实现
代码示例:
import java.io.*;
public class DynamicLoadingDemo {
public static void main(String[] args) throws Exception {
// 自定义类加载器
ClassLoader loader = new ClassLoader() {
@Override
public Class<?> findClass(String name) throws ClassNotFoundException {
try {
// 假设我们的类文件在D:/Temp/目录下
FileInputStream fis = new FileInputStream("D:/Temp/" + name + ".class");
byte[] bytes = new byte[fis.available()];
fis.read(bytes);
fis.close();
return defineClass(name, bytes, 0, bytes.length);
} catch (IOException e) {
throw new ClassNotFoundException(name);
}
}
};
// 动态加载类
Class<?> clazz = loader.loadClass("HelloWorld");
Object obj = clazz.newInstance();
// 调用方法
Method method = clazz.getMethod("sayHello");
method.invoke(obj);
}
}
// 假设D:/Temp/HelloWorld.class对应的源码是:
/*
public class HelloWorld {
public void sayHello() {
System.out.println("Hello, Dynamic Loading!");
}
}
*/
3. JNI:Java和本地语言的翻译官
大白话解释:
JNI(Java Native Interface)就像是一个翻译官,让Java能和C/C++这些本地语言对话。当Java有些事自己做不了(比如直接操作硬件),或者想用现成的C/C++库时,就可以通过JNI来调用本地代码。
特点:
- 调用本地代码(通常是C/C++)
- 性能关键部分可以用本地代码实现
- 但会失去Java的跨平台性
代码示例:
Java部分:
public class JNIDemo {
// 声明native方法
public native void sayHello();
// 加载动态链接库
static {
System.loadLibrary("hello");
}
public static void main(String[] args) {
new JNIDemo().sayHello();
}
}
C部分(需要编译为动态链接库):
#include <jni.h>
#include <stdio.h>
#include "JNIDemo.h" // 这个头文件由javac -h命令生成
JNIEXPORT void JNICALL Java_JNIDemo_sayHello(JNIEnv *env, jobject obj) {
printf("Hello from C language!\n");
return;
}
步骤:
- 编译Java文件:
javac JNIDemo.java
- 生成头文件:
javac -h . JNIDemo.java
- 编写C实现
- 编译为动态库(Windows下是DLL,Linux下是SO)
- 运行Java程序
总结对比
技术 | 比喻 | 主要用途 | 优点 | 缺点 |
---|---|---|---|---|
动态代理 | 办事中介 | AOP、日志、事务管理等 | 无需修改原有代码,灵活 | 只能代理接口 |
动态加载 | 按需带课本 | 插件系统、热部署 | 节省内存,灵活扩展 | 类加载机制复杂 |
JNI | 语言翻译官 | 调用本地库、高性能计算、硬件操作 | 访问底层功能,高性能 | 跨平台性差,安全性风险 |