127. Java 泛型 - 泛型类与子类型

127. Java 泛型 - 泛型类与子类型

1. 泛型类和接口的子类型化

在 Java 中,可以通过扩展或实现泛型类或接口来对其进行子类型化 。这意味着,如果一个类或接口是泛型的,它的类型参数将影响该类或接口的子类型关系。这个关系通过 extendsimplements 子句来决定。

示例:ArrayListList

考虑 Java 的 Collections 类库,ArrayList<E> 实现了 List<E>,而 List<E> 又扩展了 Collection<E>。因此,ArrayList<String>List<String> 的子类型,而 List<String> 又是 Collection<String> 的子类型。这是泛型类之间子类型关系的一种体现。

java 复制代码
List<String> list = new ArrayList<>();  // OK, ArrayList<String> 是 List<String> 的子类型

这就表明,当不改变类型参数时,泛型类之间会保持子类型关系。ArrayList<String>List<String> 的子类型,而 List<String> 又是 Collection<String> 的子类型。

2. 自定义泛型接口的子类型化

假设我们需要定义一个自定义的泛型接口 PayloadList,它将泛型类型 P 的值与每个元素相关联。例如,这个接口可能声明如下:

java 复制代码
interface PayloadList<E, P> extends List<E> {
    void setPayload(int index, P val);
    // 其他方法
}

在这个接口中,E 代表列表元素的类型,P 代表与每个元素相关联的"有效负载"类型。

示例:泛型接口的子类型

接下来,我们可以创建 PayloadList 的具体类型参数化版本:

java 复制代码
PayloadList<String, String> stringPayloadList = new SomePayloadListImpl<>();
PayloadList<String, Integer> integerPayloadList = new SomePayloadListImpl<>();
PayloadList<String, Exception> exceptionPayloadList = new SomePayloadListImpl<>();
  • PayloadList<String, String>List<String> 的子类型。
  • PayloadList<String, Integer>List<String> 的子类型,尽管它使用了不同的泛型类型参数。
  • PayloadList<String, Exception> 也是 List<String> 的子类型,尽管它的第二个类型参数是 Exception

解释

这里的核心概念是:只要不改变类型参数之间的相对关系,泛型类型之间就能保留子类型关系 。即使我们在泛型接口 PayloadList 中使用不同的类型参数,它们依然可以和 List<String> 保持子类型关系。关键是,类型参数 E 的一致性确保了我们可以将 PayloadList<E, P> 类型的对象赋值给 List<E> 类型的变量。

3. 泛型类和接口的类型参数

泛型类和接口的类型参数与它们的子类型关系密切相关。类型参数不仅决定了接口或类的功能,还影响了它们的继承关系和泛型约束。例如,不能将 PayloadList<String, String> 直接赋值给 PayloadList<Integer, Integer>,即使这两个类型都继承自 List<String>,因为它们的第二个类型参数不同。

java 复制代码
PayloadList<String, String> list1 = new SomePayloadListImpl<>();
PayloadList<Integer, Integer> list2 = new SomePayloadListImpl<>();

// 这将会报错,因为 list1 和 list2 不是相同类型,即使它们都继承自 List<String>。
list1 = list2;  // 编译错误,类型参数不同

4. 总结

  • 泛型类和接口的子类型化 :泛型类或接口的子类型关系由类型参数确定。只要不改变类型参数之间的关系,子类型关系就能保留。例如,ArrayList<String>List<String> 的子类型,而 List<String> 又是 Collection<String> 的子类型。
  • 自定义泛型接口 :我们可以定义自己的泛型接口,如 PayloadList,并通过不同的类型参数创建不同的子类型。这些子类型之间仍然保持继承关系。
  • 类型参数的关系:泛型类或接口的类型参数决定了它们的继承关系和可赋值性。类型参数不匹配的泛型类型不能互相赋值。

通过理解这一点,学员可以更好地理解泛型类和接口之间的继承关系,以及如何自定义泛型接口和确保类型安全。

相关推荐
devlei3 小时前
从源码泄露看AI Agent未来:深度对比Claude Code原生实现与OpenClaw开源方案
android·前端·后端
Jagger_4 小时前
周末和AI肝了两天,终于知道:为什么要把AI当做实习生
前端
weixin_456164834 小时前
vue3 子组件向父组件传参
前端·vue.js
沉鱼.444 小时前
第十二届题目
java·前端·算法
Setsuna_F_Seiei4 小时前
CocosCreator 游戏开发 - 多维度状态机架构设计与实现
前端·cocos creator·游戏开发
努力的小郑4 小时前
Canal 不难,难的是用好:从接入到治理
后端·mysql·性能优化
Bigger4 小时前
CodeWalkers:让 AI 助手化身桌面宠物,陪你敲代码的赛博伙伴!
前端·app·ai编程
Victor3565 小时前
MongoDB(87)如何使用GridFS?
后端
Victor3565 小时前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁5 小时前
单线程 Redis 的高性能之道
redis·后端