Java 零碎知识点记录

1、throw 和 throws 的区别
特性throwthrows
作用主动抛出异常对象声明方法可能抛出的异常类型
使用位置在方法体内部(代码块中)在方法声明处(方法签名末尾)
参数类型后面跟的是具体的异常对象(如 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() 判断方法来源接口
4、static 表示“属于类,而不是属于对象”。静态成员不依赖实例,也不能访问实例成员。
This article was updated on