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,并通过不同的类型参数创建不同的子类型。这些子类型之间仍然保持继承关系。
  • 类型参数的关系:泛型类或接口的类型参数决定了它们的继承关系和可赋值性。类型参数不匹配的泛型类型不能互相赋值。

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

相关推荐
YL雷子1 小时前
纯前端使用ExcelJS插件导出Excel
前端·vue·excel
什么什么什么?1 小时前
el-table高度自适应vue页面指令
前端·javascript·elementui
码上暴富5 小时前
axios请求的取消
前端·javascript·vue.js
JefferyXZF5 小时前
Next.js 初识:从 React 到全栈开发的第一步(一)
前端·全栈·next.js
你的人类朋友5 小时前
✨什么是SaaS?什么是多租户?
后端·架构·设计
M1A16 小时前
全球语言无障碍:Unicode标准解读与技术演进史
后端
无限大66 小时前
多数元素问题:从暴力美学到摩尔投票神仙解法
后端
无限大66 小时前
《计算机“十万个为什么”》之 面向对象 vs 面向过程:编程世界的积木与流水线
后端
洛可可白6 小时前
Spring Boot 应用结合 Knife4j 进行 API 分组授权管理配置
java·spring boot·后端
一只韩非子6 小时前
AI时代,程序员如何优雅地搞定页面设计?
前端·ai编程