关于一个 Java 泛型的问题

2016-12-23 17:37:05 +08:00
 pumpkin

由于 Java 泛型的擦除,经常会看到会给泛型加一个擦除的边界

<T extends X>

我想问的是:为什么不直接用多态来实现这种需求,这个擦除的边界不就相当于多态吗?

2046 次点击
所在节点    问与答
7 条回复
zhaohui318
2016-12-23 17:53:27 +08:00
看着题目眼熟,之前写过一片文章,可以参考一下

http://garywzh.xyz/2016/06/10/Java%E7%9A%84%E9%9B%86%E5%90%88%E4%B8%8E%E6%B3%9B%E5%9E%8B/
misaka19000
2016-12-23 17:54:52 +08:00
@zhaohui318 很好,学习到了
fwrq41251
2016-12-23 18:56:20 +08:00
关键词:协变
incompatible
2016-12-23 19:06:44 +08:00
@zhaohui318 把 List<Dog>转换成一个 List<Animal>的最省事儿的方式:

public List<Animal> convert(List<Dog> dogList) {
return (List) dogList;
}
21grams
2016-12-23 19:28:38 +08:00
这问题就相当于为什么用泛型不用多态
SoloCompany
2016-12-23 23:23:18 +08:00
generic / covariant / invariant

这几个概念建议都要看一下

早期的 java 没有泛型,但有数组,而数组在 java 语言里面是定义为 covariant 的,也就是赋值相容的,这其实是一个错误,因为把一个 String[] 类型转换为 Object[] 没有任何警告,但以后的元素赋值可能会产生 ClassCastException

Java 泛型的设计纠正了这个错误,是 invariant 的,也就是赋值不相容,你不能把 List<String> 直接当成 List<Object> 来用,但可以当做 List<? extends Object> 来用,自然而然, extends 和 super 关键字就是必须的了

invariant 的泛型也给编程带来很多麻烦,因为无法进行类型转换(当然,因为 java 的泛型是擦除的,强制转换并且消除警告也总是有办法做到的)

进一步的,如果你有看过 kotlin 的话,有专门章节介绍泛型, kotin 用 in / out 标记来代替了 extends / super , in / out 关键字不仅仅能修饰泛型参数类型,还能用来修饰泛型参数声明,配合不可变集合类型就能够支持 convariant 泛型(赋值相容)

比如 kotlin 的 List 是不可变的,其接口声明是 interface List<out E>;
意思是只能从里面取出来 E 类型的元素,不能保存
那么 List<String> 和 List<Object> 就变得赋值相容了
palmers
2016-12-24 07:55:21 +08:00
这个在 think in java 中有解释 泛型是 1.5 才加进来的 为了多方妥协最后采用擦出边界这么一个折中的办法

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/329744

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX