优化JAVA和Script

This commit is contained in:
estom
2025-12-21 04:21:50 -05:00
parent b868a42c7f
commit 90ac7c0893
20 changed files with 1712 additions and 49 deletions

View File

@@ -154,7 +154,7 @@ Java既需要编译也需要解释执行。
``` java
/**
* Java Doc 中的祖师格式
* Java Doc 中的注释格式
* /
```
@@ -439,7 +439,7 @@ Java定义了位运算符应用于整数类型(int),长整型(long),短
| 操作符 | 描述 | 例子 |
|---------------------|--------------------------------------------|--------------------------------|
| | 如果相对应位都是1则结果为1否则为0 | AB得到12即0000 1100 |
| | | 如果相对应位都是 0则结果为 0否则为 1 | A | B得到61即 0011 1101 |
| \| | 如果相对应位都是 0则结果为 0否则为 1 | A \| B得到61即 0011 1101 |
| ^ | 如果相对应位值相同则结果为0否则为1 | A ^ B得到49即 0011 0001 |
| 〜 | 按位取反运算符翻转操作数的每一位即0变成11变成0。 | 〜A得到-61即1100 0011 |
| <<  | 按位左移运算符。左操作数按位左移右操作数指定的位数。 | A << 2得到240即 1111 0000 |
@@ -453,8 +453,7 @@ Java定义了位运算符应用于整数类型(int),长整型(long),短
| 操作符 | 描述 | 例子 |
|------------|--------------------------------------------------|--------------------|
| && | 称为逻辑与运算符。当且仅当两个操作数都为真,条件才为真。 | A&&B为假。 |
|
`||` | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 | A`||`B为真。 |
| `\|\|` | 称为逻辑或操作符。如果任何两个操作数任何一个为真,条件为真。 | A`\|\|`B为真。 |
| | 称为逻辑非运算符。用来反转操作数的逻辑状态。如果条件为true则逻辑非运算符将得到false。 | A&&B为真。 |
* 短路运算。当使用与逻辑运算符时在两个操作数都为true时结果才为true但是当得到第一个操作为false时其结果就必定是false这时候就不会再判断第二个操作了。

View File

@@ -7,9 +7,6 @@
- [数组参数](#数组参数)
- [数组返回值](#数组返回值)
- [多维数组](#多维数组)
- [2 Arrays类](#2-arrays类)
- [方法概述](#方法概述)
- [具体方法](#具体方法)
# Java 数组
## 1 概述
@@ -120,30 +117,3 @@ s[1][0] = new String("to");
s[1][1] = new String("you");
s[1][2] = new String("!");
```
## 2 Arrays类
### 方法概述
* 给数组赋值:通过 fill 方法。
* 对数组排序:通过 sort 方法,按升序。
* 比较数组:通过 equals 方法比较数组中元素值是否相等。
* 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
### 具体方法
```java
public static int binarySearch(Object[] a, Object key)
用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)数组在调用前必须排序好的如果查找值包含在数组中则返回搜索键的索引否则返回 (-(插入点) - 1)
public static boolean equals(long[] a, long[] a2)
如果两个指定的 long 型数组彼此相等则返回 true如果两个数组包含相同数量的元素并且两个数组中的所有相应元素对都是相等的则认为这两个数组是相等的换句话说如果两个数组以相同顺序包含相同的元素则两个数组是相等的同样的方法适用于所有的其他基本数据类型ByteshortInt等
public static void fill(int[] a, int val)
将指定的 int 值分配给指定 int 型数组指定范围中的每个元素同样的方法适用于所有的其他基本数据类型ByteshortInt等
public static void sort(Object[] a)
对指定对象数组根据其元素的自然顺序进行升序排列同样的方法适用于所有的其他基本数据类型ByteshortInt等
public static void toString(array[])
依次打印元素
public static void stream()
转化成一个流
```

View File

@@ -216,7 +216,7 @@ static{
- 每次执行类,加载类的时候都会先执行静态代码块一次。
- 静态代码块是自动触发执行的,只要程序启动静态代码块就会先执行一次。
- 作用:在启动程序之前可以做资源的初始化,一般用于初始化静态资源。
- 作用:在启动程序之前可以做资源的初始化,一般用于初始化静态资源。注册驱动、加载 native 库、埋监控;
**案例演示**
@@ -242,7 +242,7 @@ public class DaimaKuaiDemo01 {
### 实例代码块
**实例代码块**
没有static修饰必须放在类下。与对象初始化一起加载。
没有static修饰必须放在类下。与对象初始化一起加载。且先于构造函数执行。
**格式**
@@ -256,8 +256,8 @@ public class DaimaKuaiDemo01 {
- 无static修饰。属于对象与对象的创建一起执行的。
- 每次调用构造器初始化对象,实例代码块都要自动触发执行一次。
- 实例代码块实际上是提取到每一个构造器中去执行的。
- 作用:实例代码块用于初始化对象的资源。
- 实例代码块实际上是提取到每一个构造器中去执行的。且先于构造函数执行。
- 作用:实例代码块用于初始化对象的资源。例如:设置复杂的初始值,
**案例演示**

View File

@@ -27,7 +27,7 @@
### Class对象
Class对象的作用
* 每个类都有一个**Class**对象,包含了与类有关的信息,代表整个字节码。代表一个类型,代表整个类。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。
* 每个类都有一个**Class**对象,包含了与类有关的信息,代表整个字节码。代表一个类型,代表整个类。当编译一个新类时,会产生一个同名的 .class 文件,该文件内容保存着 Class 对象。
* 类加载相当于 Class 对象的加载,类在第一次使用时才动态加载到 JVM 中。也可以使用 `Class.forName("com.mysql.jdbc.Driver")` 这种方式来控制类的加载,该方法会返回一个 Class 对象。
@@ -113,7 +113,6 @@ class ReflectTest02{
// 通过反射机制获取Class通过Class来实例化对象
Class c = Class.forName("javase.reflectBean.User");
// newInstance() 这个方法会调用User这个类的无参数构造方法完成对象的创建。
// 重点是newInstance()调用的是无参构造,必须保证无参构造是存在的!
Object obj = c.newInstance();
System.out.println(obj);
}

View File

@@ -14,8 +14,31 @@
- [4 泛型通配符](#4-泛型通配符)
- [5 泛型中的 KTVE](#5-泛型中的-ktve)
- [6 泛型的实现原理](#6-泛型的实现原理)
- [7 泛型实例化](#7-泛型实例化)
- [7 泛型与反射](#7-泛型与反射)
- [反射](#反射)
- [8 泛型最佳实践](#8-泛型最佳实践)
- [8.1 父类泛型化(模板基类)](#81-父类泛型化模板基类)
- [8.2 子类保留泛型(继续向下传递)](#82-子类保留泛型继续向下传递)
- [8.3 父类想“知道子类类型”CRTP自引用泛型](#83-父类想知道子类类型crtp自引用泛型)
- [9 复杂问题](#9-复杂问题)
- [复杂问题 1 类型安全地组合“处理器/策略/管道”](#复杂问题-1-类型安全地组合处理器策略管道)
- [定义泛型接口](#定义泛型接口)
- [组合(关键:通配符)](#组合关键通配符)
- [复杂问题 2泛型 + 继承做“注册表/工厂/插件”](#复杂问题-2泛型--继承做注册表工厂插件)
- [Key 用 `Class<T>`(类型令牌)](#key-用-classt类型令牌)
- [复杂问题 3泛型集合 API 设计复制、merge、填充](#复杂问题-3泛型集合-api-设计复制merge填充)
- [复制:经典 `copy`](#复制经典-copy)
- [mergeK/V 继承关系更复杂](#mergekv-继承关系更复杂)
- [复杂问题 4构建泛型数据库框架](#复杂问题-4构建泛型数据库框架)
- [复杂问题 5构建泛型缓存框架](#复杂问题-5构建泛型缓存框架)
- [复杂问题 6构建泛型事件系统](#复杂问题-6构建泛型事件系统)
- [复杂问题 7根据请求值类型定位返回值类型](#复杂问题-7根据请求值类型定位返回值类型)
- [9 常见坑与建议](#9-常见坑与建议)
- [不要在外部 API 滥用 `T extends Object`](#不要在外部-api-滥用-t-extends-object)
- [避免返回 `List<?>` 这种“无法用”的类型](#避免返回-list-这种无法用的类型)
- [数组与泛型不兼容](#数组与泛型不兼容)
- [`Optional<? extends T>` 通常没必要](#optional-extends-t-通常没必要)
- [`Comparable` 的正确写法](#comparable-的正确写法)
# 泛型机制
@@ -349,6 +372,11 @@ public class GenericMethodDemo {
Java 泛型的通配符是用于解决泛型之间引用传递问题的特殊语法。泛型与继承之间的关系
- `? extends T`**上界**(协变,用于“读”)
- `? super T`**下界**(逆变,用于“写”)
1. 无边界通配符<?>
1. 无边界的通配符的主要作用就是让泛型能够接受未知类型的数据.
2. 固定上边界的通配符<? extends E>
@@ -371,6 +399,29 @@ public class Apple<T extends A>{}
public class Apple<T supers A>{}
```
口诀:**PECS**
**P**roducer-**E**xtends生产者用 extends
**C**onsumer-**S**uper消费者用 super
例:读多写少
```java
static double sum(List<? extends Number> nums) {
double s = 0;
for (Number n : nums) s += n.doubleValue();
return s;
}
```
`List<Integer>``List<Double>` 都能传进来。
例:写入 T
```java
static void addInts(List<? super Integer> dst) {
dst.add(1);
dst.add(2);
}
```
`List<Number>``List<Object>` 都能接收 Integer。
## 5 泛型中的 KTVE
泛型中的规范
@@ -391,7 +442,7 @@ public class Apple<T supers A>{}
实际上编译器不仅关注一个泛型方法的调用,它还会为某些返回值为限定的泛型类型的方法进行强制类型转换,由于类型擦除,返回值为泛型类型的方法都会擦除成 Object 类型,当这些方法被调用后,编译器会额外插入一行 checkcast 指令用于强制类型转换,这一个过程就叫做『泛型翻译』。
## 7 泛型实例化
## 7 泛型与反射
### 反射
@@ -459,4 +510,460 @@ Class.forName(className).newInstance()
}
}
```
```
## 8 泛型最佳实践
继承体系里怎么用泛型:三种典型结构
### 8.1 父类泛型化(模板基类)
让子类指定具体类型:
```java
abstract class Repository<ID, E> {
abstract E findById(ID id);
abstract void save(E e);
}
class UserRepo extends Repository<Long, User> {
@Override User findById(Long id) { ... }
@Override void save(User u) { ... }
}
```
适合DAO、Client、Handler 这类“同一个模式,不同实体类型”。
---
### 8.2 子类保留泛型(继续向下传递)
```java
class Box<T> { T value; }
class TimedBox<T> extends Box<T> {
long time;
}
```
适合:装饰/增强、公共能力复用(缓存、计时、审计)。
---
### 8.3 父类想“知道子类类型”CRTP自引用泛型
用于**流式 API / Builder / DSL**,解决“父类方法返回子类类型”的问题:
```java
abstract class BaseBuilder<B extends BaseBuilder<B>> {
protected abstract B self();
public B withName(String name) { /*...*/ return self(); }
}
class UserBuilder extends BaseBuilder<UserBuilder> {
@Override protected UserBuilder self() { return this; }
}
```
调用方能得到正确链式类型:`new UserBuilder().withName("a")...`
---
## 9 复杂问题
### 复杂问题 1 类型安全地组合“处理器/策略/管道”
目标:一套管道把 `I -> O` 转换串起来,同时支持继承、多态组合。
#### 定义泛型接口
```java
interface Handler<I, O> {
O handle(I input);
}
```
#### 组合(关键:通配符)
组合函数:把 `Handler<A,B>``Handler<B,C>` 组合成 `Handler<A,C>`
```java
static <A, B, C> Handler<A, C> compose(
Handler<? super A, ? extends B> h1,
Handler<? super B, ? extends C> h2) {
return a -> h2.handle(h1.handle(a));
}
```
为什么这么写?
- h1 能接收 A 的父类(`? super A`
- h1 的输出是 B 的子类(`? extends B`
- h2 同理
这让组合对继承层次更“宽容”。
---
### 复杂问题 2泛型 + 继承做“注册表/工厂/插件”
目标:根据类型拿到对应实现,例如 `Service` 按请求类型分发。
#### Key 用 `Class<T>`(类型令牌)
```java
interface Processor<T> {
void process(T input);
}
class Registry {
private final Map<Class<?>, Processor<?>> map = new HashMap<>();
public <T> void register(Class<T> type, Processor<? super T> p) {
map.put(type, p);
}
@SuppressWarnings("unchecked")
public <T> Processor<T> get(Class<T> type) {
return (Processor<T>) map.get(type);
}
}
```
要点:
- `register``Processor<? super T>`:允许用更通用的处理器注册(比如处理 `Number` 的处理器也能处理 `Integer`)。
- `get` 由于类型擦除,需要一次受控的强转;对外 API 仍然是类型安全的。
---
### 复杂问题 3泛型集合 API 设计复制、merge、填充
#### 复制:经典 `copy`
```java
static <T> void copy(List<? super T> dst, List<? extends T> src) {
for (T t : src) dst.add(t);
}
```
- src 生产 T`extends`
- dst 消费 T`super`
#### mergeK/V 继承关系更复杂
```java
static <K, V> void putAll(Map<? super K, ? super V> dst,
Map<? extends K, ? extends V> src) {
for (var e : src.entrySet()) {
dst.put(e.getKey(), e.getValue());
}
}
```
### 复杂问题 4构建泛型数据库框架
```java
// 基础实体类
public abstract class BaseEntity {
private Long id;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
}
// 通用Repository接口
public interface IRepository<T extends BaseEntity> {
void save(T entity);
T findById(Long id);
List<T> findAll();
void update(T entity);
void delete(Long id);
}
// 抽象实现
public abstract class AbstractRepository<T extends BaseEntity>
implements IRepository<T> {
protected Map<Long, T> database = new HashMap<>();
protected Long idCounter = 0L;
@Override
public void save(T entity) {
entity.setId(++idCounter);
database.put(entity.getId(), entity);
}
@Override
public T findById(Long id) {
return database.get(id);
}
@Override
public List<T> findAll() {
return new ArrayList<>(database.values());
}
@Override
public void update(T entity) {
database.put(entity.getId(), entity);
}
@Override
public void delete(Long id) {
database.remove(id);
}
}
// 具体实现
public class UserRepository extends AbstractRepository<User> {
public List<User> findByName(String name) {
return findAll().stream()
.filter(user -> user.getName().equals(name))
.collect(Collectors.toList());
}
}
public class User extends BaseEntity {
private String name;
private String email;
public User(String name, String email) {
this.name = name;
this.email = email;
}
// getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getEmail() { return email; }
public void setEmail(String email) { this.email = email; }
}
// 使用
UserRepository userRepo = new UserRepository();
User user = new User("张三", "zhangsan@example.com");
userRepo.save(user);
System.out.println(userRepo.findById(1L).getName());
```
### 复杂问题 5构建泛型缓存框架
```java
// 缓存策略接口
public interface CacheStrategy<K, V> {
void put(K key, V value);
V get(K key);
void remove(K key);
void clear();
}
// LRU缓存实现
public class LRUCache<K, V> implements CacheStrategy<K, V> {
private final int capacity;
private final LinkedHashMap<K, V> cache;
public LRUCache(int capacity) {
this.capacity = capacity;
this.cache = new LinkedHashMap<K, V>(capacity, 0.75f, true) {
@Override
protected boolean removeEldestEntry(Map.Entry eldest) {
return size() > capacity;
}
};
}
@Override
public void put(K key, V value) {
cache.put(key, value);
}
@Override
public V get(K key) {
return cache.get(key);
}
@Override
public void remove(K key) {
cache.remove(key);
}
@Override
public void clear() {
cache.clear();
}
}
// 缓存管理器
public class CacheManager<K, V> {
private CacheStrategy<K, V> strategy;
public CacheManager(CacheStrategy<K, V> strategy) {
this.strategy = strategy;
}
public void set(K key, V value) {
strategy.put(key, value);
}
public V get(K key) {
V value = strategy.get(key);
if (value == null) {
// 可以从数据库加载
System.out.println("从数据库加载: " + key);
}
return value;
}
}
// 使用
CacheManager<String, User> userCache =
new CacheManager<>(new LRUCache<>(100));
User user = new User("张三", "zhangsan@example.com");
userCache.set("user:1", user);
User cached = userCache.get("user:1");
```
### 复杂问题 6构建泛型事件系统
```java
// 事件基类
public abstract class Event {
private long timestamp;
public Event() {
this.timestamp = System.currentTimeMillis();
}
public long getTimestamp() {
return timestamp;
}
}
// 具体事件
public class UserCreatedEvent extends Event {
private User user;
public UserCreatedEvent(User user) {
this.user = user;
}
public User getUser() {
return user;
}
}
// 事件监听器接口
public interface EventListener<T extends Event> {
void onEvent(T event);
}
// 事件发布器
public class EventPublisher {
private Map<Class<?>, List<EventListener<?>>> listeners =
new HashMap<>();
@SuppressWarnings("unchecked")
public <T extends Event> void subscribe(Class<T> eventType,
EventListener<T> listener) {
listeners.computeIfAbsent(eventType, k -> new ArrayList<>())
.add(listener);
}
@SuppressWarnings("unchecked")
public <T extends Event> void publish(T event) {
List<EventListener<?>> eventListeners =
listeners.get(event.getClass());
if (eventListeners != null) {
for (EventListener<?> listener : eventListeners) {
((EventListener<T>) listener).onEvent(event);
}
}
}
}
// 使用
EventPublisher publisher = new EventPublisher();
publisher.subscribe(UserCreatedEvent.class, event -> {
System.out.println("用户创建事件: " + event.getUser().getName());
});
User user = new User("李四", "lisi@example.com");
publisher.publish(new UserCreatedEvent(user));
```
### 复杂问题 7根据请求值类型定位返回值类型
“请求-响应对”+“策略分发”
```java
// 1. 标记接口Request<对应的 Response>
public interface Request<R extends Response> {}
public interface Response {}
// 2. 具体请求-响应对
public class CreateUserReq implements Request<CreateUserRsp> {
private String name;
// getter/setter
}
public class CreateUserRsp implements Response {
private Long id;
}
// 3. 处理器接口
public interface Handler<Rq extends Request<Rs>, Rs extends Response> {
Rs handle(Rq request);
}
// 4. 处理器实现
public class CreateUserHandler implements Handler<CreateUserReq, CreateUserRsp> {
@Override
public CreateUserRsp handle(CreateUserReq req) {
return new CreateUserRsp(1L);
}
}
// 5. 分发器(线程安全)
public class Dispatcher {
private final Map<Class<?>, Handler<?, ?>> map = new ConcurrentHashMap<>();
public <Rq extends Request<Rs>, Rs extends Response>
void register(Class<Rq> reqType, Handler<Rq, Rs> handler) {
map.put(reqType, handler);
}
@SuppressWarnings("unchecked")
public <Rs extends Response> Rs execute(Request<Rs> request) {
Handler<?, ?> h = map.get(request.getClass());
if (h == null) throw new IllegalArgumentException("no handler");
return ((Handler<Request<Rs>, Rs>) h).handle(request);
}
}
// 6. 使用
Dispatcher dispatcher = new Dispatcher();
dispatcher.register(CreateUserReq.class, new CreateUserHandler());
CreateUserRsp rsp = dispatcher.execute(new CreateUserReq("tom"));
System.out.println(rsp.getId());
```
## 9 常见坑与建议
### 不要在外部 API 滥用 `T extends Object`
没意义,默认就是 Object 上界。
### 避免返回 `List<?>` 这种“无法用”的类型
返回 `List<T>``List<? extends Base>` 更实用。
### 数组与泛型不兼容
`new T[]` 不允许;用 `List<T>` 或传 `IntFunction<T[]>` / `Class<T>` 创建。
### `Optional<? extends T>` 通常没必要
多用 `Optional<T>`;在参数处才常用通配符。
### `Comparable` 的正确写法
```java
class A implements Comparable<A> { ... }
```
如果写工具方法:
```java
static <T extends Comparable<? super T>> T max(List<? extends T> list) { ... }
```

View File

@@ -0,0 +1,27 @@
## 1 Arrays类
### 方法概述
* 给数组赋值:通过 fill 方法。
* 对数组排序:通过 sort 方法,按升序。
* 比较数组:通过 equals 方法比较数组中元素值是否相等。
* 查找数组元素:通过 binarySearch 方法能对排序好的数组进行二分查找法操作。
### 具体方法
```java
public static int binarySearch(Object[] a, Object key)
用二分查找算法在给定数组中搜索给定值的对象(Byte,Int,double等)数组在调用前必须排序好的如果查找值包含在数组中则返回搜索键的索引否则返回 (-(插入点) - 1)
public static boolean equals(long[] a, long[] a2)
如果两个指定的 long 型数组彼此相等则返回 true如果两个数组包含相同数量的元素并且两个数组中的所有相应元素对都是相等的则认为这两个数组是相等的换句话说如果两个数组以相同顺序包含相同的元素则两个数组是相等的同样的方法适用于所有的其他基本数据类型ByteshortInt等
public static void fill(int[] a, int val)
将指定的 int 值分配给指定 int 型数组指定范围中的每个元素同样的方法适用于所有的其他基本数据类型ByteshortInt等
public static void sort(Object[] a)
对指定对象数组根据其元素的自然顺序进行升序排列同样的方法适用于所有的其他基本数据类型ByteshortInt等
public static void toString(array[])
依次打印元素
public static void stream()
转化成一个流
```

View File

@@ -0,0 +1,195 @@
自引用泛型Self-referential generics / F-bounded polymorphism很多人也叫 CRTP 风格)指:**类型参数的上界本身又引用了这个类型参数**,典型形态是:
```java
class Base<T extends Base<T>> { ... }
```
含义:`T` 必须是“某个继承自 `Base<T>` 的类型”,从而让 Base 在编译期“知道”子类的精确类型。
---
## 1 要解决什么问题:父类方法想返回“子类类型”
### 没用自引用泛型时的问题
```java
class Base {
Base withName(String n) { return this; }
}
class UserBuilder extends Base { }
UserBuilder b = new UserBuilder();
b.withName("a") // 返回 Base
.withName("b"); // 链式调用类型会退化成 Base
```
你会失去子类特有方法的链式调用:
```java
b.withName("a").onlyInUser(); // 编译不过,因为 withName 返回 Base
```
### 用自引用泛型(让返回类型保持为子类)
```java
abstract class Base<B extends Base<B>> {
protected abstract B self();
public B withName(String n) {
// ... set field
return self();
}
}
class UserBuilder extends Base<UserBuilder> {
@Override protected UserBuilder self() { return this; }
public UserBuilder onlyInUser() { return this; }
}
```
现在:
```java
new UserBuilder()
.withName("a")
.onlyInUser()
.withName("b");
```
链式调用始终保持 `UserBuilder` 类型。
---
## 2 它到底“类型上”在约束什么?
这句:
```java
B extends Base<B>
```
表示:`B` 不是随便的类型,它必须满足:
- `B``Base<B>` 的子类型
所以 `class UserBuilder extends Base<UserBuilder>` 合法;
`class X extends Base<String>` 不合法String 不是 Base<String>)。
这种约束让 Base 能安全地把 `this` 视作 `B`(通过 `self()` 或强转),从而在 Base 里写出“返回子类”的 API。
---
## 3 为什么需要 `self()`?能不能直接 `(B) this`
可以强转,但不推荐暴露在公共基类里。
### 方案 A强转常见但有风险
```java
abstract class Base<B extends Base<B>> {
@SuppressWarnings("unchecked")
protected B self() { return (B) this; }
public B withName(String n) { return self(); }
}
```
风险在于:如果有人写了“破坏约束”的继承结构(通过原始类型 raw type 绕过),运行期可能 `ClassCastException`
### 方案 B子类实现 self更稳
```java
abstract class Base<B extends Base<B>> {
protected abstract B self();
}
```
子类返回 `this`,不需要 unchecked cast更清晰。
---
## 4 典型使用场景
### 4.1 Builder / Fluent API最常见
让基类提供通用链式方法name、id、tags…子类还能追加自身方法且不中断链式。
### 4.2 “可比较/可排序”这类自类型约束JDK 经典)
`Comparable` 是个“弱化版”案例:
```java
class MyType implements Comparable<MyType> { ... }
```
工具方法里常见约束:
```java
static <T extends Comparable<? super T>> T max(List<? extends T> list) { ... }
```
这也是为了兼容继承关系(`? super T`)。
### 4.3 框架基类返回子类、注册子类、DSL
例如:
- ORM/Query DSL`Query<T extends Query<T>> where(...)`
- 图结构/节点 API`Node<N extends Node<N>> addChild(N child)`
---
## 5 多层继承时怎么写?
你可以把“自类型参数”一路传下去:
```java
abstract class Base<B extends Base<B>> {
protected abstract B self();
public B common() { return self(); }
}
abstract class Mid<B extends Mid<B>> extends Base<B> {
public B mid() { return self(); }
}
class Concrete extends Mid<Concrete> {
@Override protected Concrete self() { return this; }
public Concrete only() { return this; }
}
```
调用:`new Concrete().common().mid().only();` 都保持 `Concrete`
---
## 6 常见坑
### 6.1 原始类型raw type会破坏类型安全
```java
class Bad extends Base { // 使用 raw type
@Override protected Base self() { return this; }
}
```
这会导致泛型约束失效,可能埋下运行期强转问题。尽量禁止 raw type。
### 6.2 “写错自类型”导致诡异编译错误
```java
class A extends Base<B> { ... } // B 不是 A
```
自引用泛型的关键是:**参数必须是“自己”**(或至少保持一致的自类型),一般写成 `extends Base<当前类名>`
### 6.3 组合composition有时比继承更简单
如果只是想链式配置,有时用组合/返回 `this` 并配合接口也能做,别为了泛型而泛型。
---
## 7 一个更完整的“可复用 Builder 基类”例子
```java
abstract class Builder<B extends Builder<B>> {
protected String name;
protected int age;
protected abstract B self();
public B name(String n) { this.name = n; return self(); }
public B age(int a) { this.age = a; return self(); }
}
class UserBuilder extends Builder<UserBuilder> {
private String email;
@Override protected UserBuilder self() { return this; }
public UserBuilder email(String e) { this.email = e; return this; }
public User build() { return new User(name, age, email); }
}
```