
Java 零碎知识点记录
1、throw 和 throws 的区别
| 特性 | throw | throws |
|---|---|---|
| 作用 | 主动抛出异常对象 | 声明方法可能抛出的异常类型 |
| 使用位置 | 在方法体内部(代码块中) | 在方法声明处(方法签名末尾) |
| 参数类型 | 后面跟的是具体的异常对象(如 new Exception()) | 后面跟的是异常类名(如 IOException) |
| 数量限制 | 每次只能抛出一个异常 | 可以声明多个异常类型(用逗号分隔) |
| 执行流程 | 抛出后,方法立即终止,异常向上传递 | 仅声明可能性,告知调用者可能抛出异常 |
2、介绍一下抽象类
抽象类用 abstract class ClassName {} 声明,抽象方法不能写实现。
- 子类必须实现抽象类中的所有抽象方法(除非子类也是抽象类)。
- 如果未完全实现抽象方法,子类必须声明为抽象类。
- 抽象类不能通过
new创建对象。
abstract class Animal {
// 抽象方法(没有方法体)
public abstract void makeSound();
// 具体方法(有方法体)
public void sleep() {
System.out.println("Sleeping...");
}
}| 特性 | 抽象类 | 接口 |
|---|---|---|
| 定义 | 用 abstract 关键字声明 | 用 interface 关键字声明 |
| 方法体 | 可以包含具体方法和抽象方法。 | 默认全是抽象方法(Java 8 前) |
| 字段 | 可以定义任意字段(如 private) | 默认是 public static final |
| 构造器 | 可以有构造方法 | 不能有构造方法 |
| 继承 | 一个类只能继承一个抽象类 | 一个类可以实现多个接口 |
| 访问修饰符 | 方法和字段可以使用任意访问修饰符 | 方法默认是 public |
| 适用场景 | 自下而上的抽象 | 自上而下的约定 |
3、动态代理
特点:无侵入式地给代码增加额外的功能
- JDK 动态代理只能代理接口
- 如果需要代理类而非接口,需要使用 CGLIB 等第三方库
- 动态代理是实现 AOP(面向切面编程)的基础技术之一
① 定义接口(包含多个方法)
interface Subject {
void sayHello(String name);
int add(int a, int b);
String concatenate(String s1, String s2);
}② 接口实现类
class RealSubject implements Subject {
@Override
public void sayHello(String name) {
System.out.println("Hello, " + name + "!");
}
@Override
public int add(int a, int b) {
return a + b;
}
@Override
public String concatenate(String s1, String s2) {
return s1 + s2;
}
}③ 自定义 InvocationHandler(代理逻辑)
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
class MyInvocationHandler implements InvocationHandler {
private final Object target;
public MyInvocationHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result;
// 前置处理
System.out.println("Before calling method: " + method.getName());
// 根据方法名执行不同的逻辑
if (method.getName().equals("sayHello")) {
System.out.println("Executing sayHello with name: " + args[0]);
} else if (method.getName().equals("add")) {
System.out.println("Adding " + args[0] + " and " + args[1]);
} else if (method.getName().equals("concatenate")) {
System.out.println("Concatenating " + args[0] + " and " + args[1]);
}
// 调用实际方法
result = method.invoke(target, args);
// 后置处理
System.out.println("After calling method: " + method.getName());
System.out.println();
return result;
}
}④ 测试类
public class DynamicProxyDemo {
public static void main(String[] args) {
// 创建真实对象
Subject realSubject = new RealSubject();
// 创建InvocationHandler
InvocationHandler handler = new MyInvocationHandler(realSubject);
// 创建代理对象
Subject proxySubject = (Subject) java.lang.reflect.Proxy.newProxyInstance(
Subject.class.getClassLoader(),
new Class<?>[]{Subject.class},
handler
);
// 调用多个方法
proxySubject.sayHello("Alice");
int sum = proxySubject.add(3, 5);
String combined = proxySubject.concatenate("Java", "Proxy");
System.out.println("Add result: " + sum);
System.out.println("Concatenated result: " + combined);
}
}⑤ 运行结果
Before calling method: sayHello
Executing sayHello with name: Alice
Hello, Alice!
After calling method: sayHello
Before calling method: add
Adding 3 and 5
After calling method: add
Before calling method: concatenate
Concatenating Java and Proxy
After calling method: concatenate
Add result: 8
Concatenated result: JavaProxy动态代理同时实现多个接口:
| 特性 | 说明 |
|---|---|
| 多接口支持 | 通过 Proxy.newProxyInstance() 的第二个参数传入多个接口 |
| 方法拦截统一 | 所有接口的方法调用都会经过 invoke() 方法 |
| 接口识别 | 可通过 method.getDeclaringClass() 判断方法来源接口 |
