Skip to content

Advanced of Java

泛型(generics)

java
// 泛型类
public class Box<T> {
    private T content;
    
    public void set(T content) {
        this.content = content;
    }
    
    public T get() {
        return content;
    }
}

// 使用
Box<String> stringBox = new Box<>();
stringBox.set("hello");
// 无需强制类型转换
String s = stringBox.get();  

// 泛型方法
public <T> void printArray(T[] array) {
    for (T item : array) {
        System.out.println(item);
    }
}

// 任意类型
List<?> unknownList;
// Number 或其子类(上界)
List<? extends Number> numbers;
// Integer 或其父类(下界)
List<? super Integer> integers;

反射(Reflection)

反射是 Java 在运行时动态获取类的信息并操作类对象的能力。它打破了 Java 的封装性,让程序可以:

  • 在运行时知道任意对象的类信息
  • 构造任意类的对象
  • 调用任意对象的方法
  • 访问和修改任意字段的值

核心类java.lang.reflect 包下的 ClassFieldMethodTypeConstructorAnnotation

一些用例:

Spring 依赖注入

java
public class DependencyInjector {
    public void inject(Object obj) throws Exception {
        Class<?> clazz = obj.getClass();
        
        // 扫描所有字段,找到 @Autowired 注解的
        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(Autowired.class)) {
                field.setAccessible(true);
                // 从容器中获取 Bean 并注入
                Object bean = getBeanFromContainer(field.getType());
                field.set(obj, bean);
            }
        }
    }
}

动态代理(AOP 实现基础)

java
// JDK 动态代理(基于反射)
public interface UserService {
    void addUser();
}

public class UserServiceImpl implements UserService {
    public void addUser() {
        System.out.println("添加用户");
    }
}

// 创建代理
UserService proxy = (UserService) Proxy.newProxyInstance(
    UserService.class.getClassLoader(),
    new Class<?>[] { UserService.class },
    (proxyObj, method, args) -> {
        System.out.println("前置通知");
        Object result = method.invoke(new UserServiceImpl(), args);
        System.out.println("后置通知");
        return result;
    }
);

// 实现原方法前后切入其他动作
proxy.addUser();

序列化/反序列化(JSON 转化)

java
public <T> T jsonToObject(String json, Class<T> clazz) throws Exception {
    T instance = clazz.getDeclaredConstructor().newInstance();
    // json to map
    Map<String, Object> map = parseJson(json);
    
    for (Field field : clazz.getDeclaredFields()) {
        field.setAccessible(true);
        String fieldName = field.getName();
        if (map.containsKey(fieldName)) {
            field.set(instance, map.get(fieldName));
        }
    }
    return instance;
}

测试单元(JUnit )

java
public class TestRunner {
    public static void runTests(Class<?> testClass) throws Exception {
        Object instance = testClass.getDeclaredConstructor().newInstance();
        
        for (Method method : testClass.getDeclaredMethods()) {
            if (method.isAnnotationPresent(Test.class)) {
                // 执行 @Test 标记的方法
                method.invoke(instance);
            }
            
            if (method.isAnnotationPresent(BeforeEach.class)) {
                // 执行前置方法
                method.invoke(instance);
            }
        }
    }
}

配置文件驱动(解耦)

java
// config.properties
// driver.class=com.mysql.cj.jdbc.Driver
// service.class=com.example.UserServiceImpl

Properties props = new Properties();
props.load(new FileInputStream("config.properties"));

// 动态加载类
Class<?> driverClass = Class.forName(props.getProperty("driver.class"));
Driver driver = (Driver) driverClass.getDeclaredConstructor().newInstance();

Class<?> serviceClass = Class.forName(props.getProperty("service.class"));
Object service = serviceClass.getDeclaredConstructor().newInstance();

流(Stream)

Stream 是元素的序列,支持串行或并行的聚合操作:

  • 不存储数据 - 元素来自数据源(集合、数组、I/O 等)
  • 不改变源数据 - 返回新 Stream 或结果
  • 惰性求值 - 中间操作延迟到终止操作才执行
  • 一次消费 - 遍历后不能重复使用

parallel stream 数据量大(通常 > 10,000)时考虑并行

创建

java
IntStream intStream = Arrays.asList(1, 2, 3).stream();
Stream<String> stream3 = Stream.of("a", "b", "c");
IntStream intStream = IntStream.range(1, 5);      // 1,2,3,4
IntStream intStream = IntStream.rangeClosed(1, 5); // 1,2,3,4,5
// 无限流(配合 limit 使用)
Stream<Integer> infinite = Stream.iterate(0, n -> n + 2); // 0,2,4,6...
Stream<Double> randoms = Stream.generate(Math::random);

中间操作

java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5, 6, 2, 3);

// 条件过滤
numbers.stream()
	   .filter(n -> n % 2 == 0)  // 偶数
	   .forEach(System.out::println); // 2,4,6,2

// 去重
numbers.stream()
	   .distinct()
	   .collect(Collectors.toList()); // [1,2,3,4,5,6]

// 截取
numbers.stream()
	   .limit(3)
	   .collect(Collectors.toList()); // [1,2,3]

// 跳过
numbers.stream()
	   .skip(3)
	   .collect(Collectors.toList()); // [4,5,6,2,3]

// 类似分页
numbers.stream()
	   .skip(3)
	   .limit(3)
	   .collect(Collectors.toList()); // [4,5,6]

映射

java
class User {
	int age;
	String name;
}

List<User> arr;

List<String> names = arr.stream()
	.map(User::getName)
	.collect(Collector.toList());

// 扁平化
// 将 [[1,2], [3,4], [5,6]] 扁平化为 [1,2,3,4,5,6]
List<Integer> arr = Arrays.asList(
				Arrays.asList(1, 2),
				Arrays.asList(3, 4),
				Arrays.asList(5, 6)
		).stream()
		.flatMap(List::stream)
		.collect(Collectors.toList());
		
// ["Hello World", "Java Stream"] -> [Hello, World, Java, Stream]
List<String> arr = Arrays.asList("Hello World", "Java Stream").stream()
	.flatMap(s -> Arrays.stream(s.split(" ")))
	.collect(Collectors.toList());

排序

java
// 自然排序 [apple, banana, cherry, date]
Arrays.asList("banana", "apple", "cherry", "date").stream()
	  .sorted()
	  .collect(Collectors.toList());

// 自定义比较器
// 倒序
sorted(Comparator.reverseOrder())
// 按长度
sorted(Comparator.comparing(String::length))
// 多字段排序
sorted(...)
.thenComparing(..);

遍历与匹配

java
List<Integer> arr = Arrays.asList(1, 2, 3, 4, 5);
        
// forEach - 遍历
arr.stream().forEach(System.out::println);

// 匹配操作(短路求值)
boolean anyEven = arr.stream().anyMatch(n -> n % 2 == 0);
boolean allPositive = arr.stream().allMatch(n -> n > 0);
boolean noNegative = arr.stream().noneMatch(n -> n < 0);

// findFirst / findAny
Optional<Integer> first = arr.stream()
	.filter(n -> n > 3)
	.findFirst();  
// // 并行时可能返回 4 或 5
Optional<Integer> any = arr.parallelStream()
	.filter(n -> n > 3)
	.findAny();

归约

java
List<Integer> arr = Arrays.asList(1, 2, 3, 4, 5);

// 求和
int sum1 = arr.stream().reduce(0, (a, b) -> a + b);
int sum2 = arr.stream().reduce(0, Integer::sum);
Optional<Integer> sum3 = arr.stream().reduce(Integer::sum);

// 乘积
int product = arr.stream().reduce(1, (a, b) -> a * b);

// 字符串连接
String joined = Stream.of("a", "b", "c")
	.reduce("", String::concat);

// 最大值/最小值
Optional<Integer> max = arr.stream().reduce(Integer::max);

// 复杂归约:统计
int[] stats = arr.stream().reduce(
	new int[]{0, 0},                   
	(acc, n) -> new int[]{acc[0] + n, acc[1] + 1},
	(a, b) -> new int[]{a[0] + b[0], a[1] + b[1]}  
);
double avg = (double) stats[0] / stats[1];

收集器

java

class User {
	int age;
	String gender;
	String name;
}

List<User> arr;
// toList、toSet、toCollection
LinkedHashSet set = arr.stream().collect(Collector.toCollection(LinkedHashSet::new));

// toMap

// joining
String str = arr.stream()  
        .map(User::getName)  
        .collect(Collectors.joining(", ", "[", "]"));

// groupingBy
Map<String, List<User>> byGender = users.stream()
		.collect(Collectors.groupingBy(User::getGender));
// 分组聚合
Map<String, Double> avgAgeByGender = arr.stream()  
        .collect(Collectors.groupingBy(  
                User::getGender,  
                Collectors.averagingInt(User::getAge)  
        ));
// 分区-partitingBy
Map<Boolean, List<User>> partitioned = arr.stream()  
        .collect(Collectors.partitioningBy(u -> u.getAge() >= 30));
// 多级分区
Map<String, Map<Integer, List<User>>> multiLevel = arr.stream()  
        .collect(Collectors.groupingBy(  
                User::getGender,  
                Collectors.groupingBy(User::getAge)  
        ));
        
// 统计
IntSummaryStatistics stats = arr.stream()  
        .collect(Collectors.summarizingInt(User::getAge));  
// count=4, sum=118, min=25, average=29.5, max=35

// 聚合-reducing   
Integer totalAge = arr.stream()  
        .collect(Collectors.reducing(0, User::getAge, Integer::sum));

并发

特性进程 (Process)线程 (Thread)
资源占用独立地址空间,资源开销大共享进程资源,开销小
通信方式IPC(管道、套接字、共享内存等)直接共享内存,需同步机制
切换开销大(需切换页表)小(只需保存寄存器)
崩溃影响不影响其他进程可能导致整个进程崩溃

线程状态

Java 线程有 6 种状态(定义在 java.lang.Thread.State 枚举中)

NEW -> RUNNABLE -> (BLOCKED/WAITING/TIMED_WAITING) -> TERMINATED

plain
			┌───────┐
			│ NEW   │
			└──┬────┘
			   │ start()

		  ┌─────────┐     ┌──────────┐
	 ┌────┤ RUNNABLE├────►│ RUNNING  │◄────┐
	 │    └────┬────┘     └──────────┘     │
	 │         │                           │
	 │    ┌────┴────┐                      │
	 │    │         │                      │
	 │    ▼         ▼                      │
	 │ ┌───────┐ ┌─────────┐               │
	 └─┤BLOCKED│ │ WAITING │◄──────────────┘
	   └───┬───┘ └────┬────┘  notify()/notifyAll()
		   │          │
		   │    ┌─────┴─────────┐
		   │    │ TIMED_WAITING │
		   │    └─────┬─────────┘
		   │          │
		   └──────────┘
			   │ 获取锁 / 被唤醒 / 超时

		  ┌──────────┐
		  │TERMINATED│
		  └──────────┘

生命周期

Thread t = new Thread(() -> {});

方法作用状态变化
t.start()启动线程NEW → RUNNABLE
t.join()等待该线程执行完毕RUNNABLE → WAITING/TIMED_WAITING
Thread.yield()让出 CPU,进入就绪态RUNNABLE → RUNNABLE(可能)
Thread.sleep(long)休眠指定毫秒,不释放锁RUNNABLE → TIMED_WAITING → RUNNABLE

中断与终止

方法作用注意
t.interrupt()设置中断标志位不会真正停止线程,只是发信号
t.isInterrupted()检查中断状态不清除标志位
Thread.interrupted()检查并清除中断状态静态方法
t.stop()已废弃不安全,可能导致资源泄漏
t.suspend()已废弃不安全,可能导致资源泄漏
t.resume()已废弃不安全,可能导致资源泄漏

Object 等待与通知(同步块中使用)

方法作用状态变化
wait()释放锁,无限等待RUNNABLE → WAITING
wait(long timeout)释放锁,限时等待RUNNABLE → TIMED_WAITING
notify()唤醒一个等待线程WAITING → BLOCKED(需重新获取锁)
notifyAll()唤醒所有等待线程WAITING → BLOCKED
java
public class ThreadStateDemo {
    public static void main(String[] args) throws Exception {
        Object lock = new Object();
        
        Thread t1 = new Thread(() -> {
            synchronized (lock) {
                try {
                    System.out.println("t1 进入 WAITING");
                    lock.wait();  
                    System.out.println("t1 被唤醒,尝试获取锁...");
                    // 这里可能 BLOCKED,如果 t2 还没释放锁
                    Thread.sleep(1000); // TIMED_WAITING
                    
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("t1 结束");
        });
        
        Thread t2 = new Thread(() -> {
            synchronized (lock) {
                System.out.println("t2 持有锁,准备唤醒 t1");
                 // 唤醒 t1,但 t1 需等待 t2 释放锁
                lock.notify();
                try {
	                 // 模拟耗时操作,t1 此时是 BLOCKED
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("t2 释放锁");
            }
        });
        
        System.out.println("t1 NEW: " + t1.getState());
        t1.start();
        // 确保 t1 先执行
        Thread.sleep(100); 
        // WAITING
        System.out.println("t1 WAITING: " + t1.getState()); 
        t2.start();
        // BLOCKED(等待 t2 释放)
        System.out.println("t1 BLOCKED: " + t1.getState()); 锁)
        // 等待 t1 执行完毕
        t1.join();
        // TERMINATED
        System.out.println("t1 TERMINATED: " + t1.getState()); 
    }
}

多线程

java
// 1. 继承 Thread 类(不推荐,单继承限制)
class MyThread extends Thread {
    @Override
    public void run() {
        System.out.println("线程运行");
    }
}
MyThread t1 = new MyThread();
t1.start();

// 2. 实现 Runnable 接口(推荐)
class MyRunnable implements Runnable {
    @Override
    public void run() {
        System.out.println("线程运行");
    }
}
Thread t2 = new Thread(new MyRunnable());
t2.start();

// 3. 实现 Callable 接口(有返回值)
class MyCallable implements Callable<String> {
    @Override
    public String call() throws Exception {
        return "任务完成";
    }
}
FutureTask<String> futureTask = new FutureTask<>(new MyCallable());
new Thread(futureTask).start();
String result = futureTask.get();  // 阻塞获取结果

// Lambda 简化(Java 8+)
new Thread(() -> System.out.println("线程运行")).start();

线程同步

为了避免多个线程同时访问共享资源时导致数据不一致的问题。由于线程的调度由操作系统决定,多个线程可能在任意时刻被中断或切换,因此需要通过同步机制来确保线程安全。

线程安全 线程同步的核心是原子性,即一组操作必须不可分割地执行,其他线程在此期间无法干扰。为实现这一点,通常使用锁机制来保护共享资源。加锁的代码块称为临界区,在同一时刻只能有一个线程进入。