企业级公共SDK泛型设计核心是保障调用方安全、减少错误、便于升级;需严格遵循PECS原则、协变接口优先、并发容器泛型带边界、插件扩展不暴露泛型构造逻辑。

企业级公共 SDK 的泛型设计,核心不是“让类型更灵活”,而是“让调用方更安全、更少出错、更易升级”。泛型一旦暴露到 SDK 接口层,就成为契约的一部分——改一个通配符,可能影响成百上千个下游系统。
严格按 PECS 原则声明集合参数
SDK 中所有涉及泛型集合的入参和返回值,必须明确读写角色,禁用裸泛型(如 List<t></t>):
-
只读场景(如回调数据、查询结果)→ 使用
List<? extends T>:允许用户传ArrayList<OrderEvent>给期望Event的接口,保持多态兼容性; -
只写场景(如批量提交、缓冲注入)→ 使用
Collection<? super T>:支持用户传ArrayDeque<BaseMetricPoint>接收MetricPoint子类,避免强转或原始类型降级; -
读写混合 → 拆成两个方法:例如
ingest(Collection<? super LogEntry>)+drain(): List<? extends ProcessedLog>,不妥协、不模糊。
协变接口优先,禁用泛型类协变
Java 不支持泛型类协变,但接口可以声明 interface IProducer<out T>(C#)或等效的 Java 风格抽象——在 Java 中通过 extends 约束 + 明确只读契约模拟:
- 只在返回值、
get()方法、流式输出中使用类型参数; - 禁止在方法参数、
set()、构造器、字段中出现该类型; - 定义
IEventProducer<T extends IEvent>,用户实现PaymentEventProducer后,可直接注入依赖IEventProducer<IEvent>的模块,天然向前兼容。
并发容器泛型必须带边界,避免擦除引发运行时异常
高并发 SDK 常用 ConcurrentHashMap、CopyOnWriteArrayList,泛型擦除在多线程下会放大类型风险:
立即学习“Java免费学习笔记(深入)”;
- 缓存 key 若为业务 ID 类型,声明为
ConcurrentHashMap<? super BusinessId, ? extends CacheValue>,确保OrderId子类也能安全命中; - Stream 收集结果需显式指定容器类型:
.collect(Collectors.toCollection(() -> new CopyOnWriteArrayList<ProcessedResult>())),而非依赖toList()返回的List<Object>; - 自定义并发结构(如带版本控制的队列)泛型参数必须加约束,如
class VersionedQueue<T extends Serializable>。
插件与扩展点不暴露泛型构造逻辑
SDK 提供 SPI 扩展能力时,泛型应由编译期静态约束,而非运行时动态构造:
- 工厂方法返回协变接口,如
<T extends Plugin> T loadPlugin(Class<T> type),而非接受String className再反射创建; - 配置项中禁止让用户填写泛型类型全名字符串;改用约定命名(如
plugin.type=auth-jwt)或程序集扫描自动注册; - 不提供
createInstance(Type type)这类绕过泛型检查的 API,防止下游用反射破坏类型安全。


















