Appearance
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 包下的 Class、Field、Method、Type、Constructor、Annotation 等
一些用例:
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();线程同步
为了避免多个线程同时访问共享资源时导致数据不一致的问题。由于线程的调度由操作系统决定,多个线程可能在任意时刻被中断或切换,因此需要通过同步机制来确保线程安全。
线程安全 线程同步的核心是原子性,即一组操作必须不可分割地执行,其他线程在此期间无法干扰。为实现这一点,通常使用锁机制来保护共享资源。加锁的代码块称为临界区,在同一时刻只能有一个线程进入。