Java接口配合泛型通配符的核心在于让接口方法的参数或返回值接受更宽泛但有约束的类型范围,保持类型安全且避免过度限定;关键是在使用接口时(而非定义时)用上界(? extends T)、下界(? super T)或嵌套通配符放宽兼容性。

接口方法参数用上界通配符:接收子类型集合
当接口方法需要处理“某种类型及其所有子类”的数据时,用 ? extends T。
- 例如定义一个只读数据处理器接口:
public interface DataReader { void readAll(List<? extends Number> numbers); }- 这样,
readAll(new ArrayList<Integer>())、readAll(new ArrayList<Double>())都合法;但不能往numbers里 add 任何元素(编译器不知道具体是哪种 Number 子类)。 - 适合“消费”数据(只读),不修改集合内容。
接口方法参数用下界通配符:支持向父类型集合写入
当接口方法要往集合中添加统一类型的数据,而该集合可能是其父类类型时,用 ? super T。
- 例如一个日志记录器接口:
public interface Logger { void logAll(List<? super String> targets, List<String> logs); }- 它允许传入
ArrayList<Object>或ArrayList<CharSequence>作为targets,因为两者都可存入String;但不能从中安全 get 出 String(只能当作 Object 处理)。 - 适合“生产”数据(写入),强调类型可接纳性。
接口作为泛型类型参数时嵌套通配符:增强组合灵活性
当接口本身是泛型(如 Function<T, R>、Predicate<E>),在方法签名中将其与通配符结合,能解耦实现细节。
- 例如一个通用过滤服务:
public <T> List<T> filter(List<T> data, Predicate<? super T> predicate)- 这里
Predicate<? super T>表示:只要谓词能处理T或它的任意父类,就可接受。比如T=LocalDateTime,传入Predicate<Temporal>(父接口)完全合法。 - 这比写死
Predicate<T>更灵活,且仍保有类型安全——编译器确保谓词不会误判T的行为。
List<? extends X> 作为字段——那会失去泛型的类型推导能力。真正起作用的是调用方如何用通配符“适配”已有的泛型接口。


















