锁定老帖子 主题:关于Java泛型 与 类型推断
精华帖 (0) :: 良好帖 (3) :: 新手帖 (1) :: 隐藏帖 (12)
|
|
---|---|
作者 | 正文 |
发表时间:2012-02-14
RednaxelaFX 写道 amoszhou 写道 RednaxelaFX 写道 楼主需要的是PECS口诀。《Effective Java》第二版原文版的136页。
大神,这个还真不是需要口诀。 如果只是背口诀我就不用来问了。 口诀是为了帮助记忆用的。很明显你没理解Java泛型里covariance(协变)和contravariance(逆变)的特性的影响。PECS口诀正是帮助记忆这个用的。当然,肯不肯去看是你自己决定的事情咯 顺带一提,Java泛型的variance是同时支持use-site variance和declaration-site variance的。而正是use-site variance让楼主头疼了。后来C#支持variance的时候就没用这么复杂的设计,而是只支持declaration-site variance,就没这种问题。反正就是语言设计中的各种取舍。 如果对背景完全没了解可以找些问答帖看,例如这个:http://stackoverflow.com/questions/4231305/how-does-javas-use-site-variance-compare-to-cs-declaration-site-variance 别外,大神看下IBM的这篇文章: http://www.ibm.com/developerworks/cn/java/j-jtp04298.html 里面有这么一句话: 通配符在类型系统中的作用部分来自其不会发生协变(covariant)这一特性。数组是协变的,因为 Integer 是 Number 的子类型,数组类型 Integer[] 是 Number[] 的子类型,因此在任何需要 Number[] 值的地方都可以提供一个 Integer[] 值。另一方面,泛型不是协变的, 作者说泛型不是协变的。。那不是和你说的冲突了? |
|
返回顶楼 | |
发表时间:2012-02-14
另外本人很讨厌JavaEye的部分人。。动不动就投个隐藏贴票。你敢说你真的问题你真的从原理上明白了?
只知道死背硬记谁不会? 对问题只知其然,并不知其所以然。 |
|
返回顶楼 | |
发表时间:2012-02-14
帖子很好 至少学会了两个名词 协变和逆变
虽然看了定义发现以前也知道那么回事。。。。。 java的数组确实是协变的,泛型应该不是吧 List<String>不能赋值给List<Object>变量 泛型应该是不可变的吧,起码应该不支持declaration-site variance的吧 谁能解释下。。。最好通俗点的。。。 |
|
返回顶楼 | |
发表时间:2012-02-14
amoszhou 写道 RednaxelaFX 写道 amoszhou 写道 RednaxelaFX 写道 楼主需要的是PECS口诀。《Effective Java》第二版原文版的136页。
大神,这个还真不是需要口诀。 如果只是背口诀我就不用来问了。 口诀是为了帮助记忆用的。很明显你没理解Java泛型里covariance(协变)和contravariance(逆变)的特性的影响。PECS口诀正是帮助记忆这个用的。当然,肯不肯去看是你自己决定的事情咯 顺带一提,Java泛型的variance是同时支持use-site variance和declaration-site variance的。而正是use-site variance让楼主头疼了。后来C#支持variance的时候就没用这么复杂的设计,而是只支持declaration-site variance,就没这种问题。反正就是语言设计中的各种取舍。 如果对背景完全没了解可以找些问答帖看,例如这个:http://stackoverflow.com/questions/4231305/how-does-javas-use-site-variance-compare-to-cs-declaration-site-variance 别外,大神看下IBM的这篇文章: http://www.ibm.com/developerworks/cn/java/j-jtp04298.html 里面有这么一句话: 通配符在类型系统中的作用部分来自其不会发生协变(covariant)这一特性。数组是协变的,因为 Integer 是 Number 的子类型,数组类型 Integer[] 是 Number[] 的子类型,因此在任何需要 Number[] 值的地方都可以提供一个 Integer[] 值。另一方面,泛型不是协变的, 作者说泛型不是协变的。。那不是和你说的冲突了? 你或许太性急了,先冷静下来整理一下你已经理解的 现成的讲解太多了,本来懒得增添杂音… 在Java里,不带super和extends的泛型是不协变的。所以,如果有: public interface List<E> { } public class Fruit { } public class Apple extends Fruit { } 那么Apple是Fruit的子类型,但List<Apple>不是List<Fruit>的子类型。这里体现了泛型的不协变性。 但是这样有时候会很尴尬。如果要写一个通用的方法,本来可以放个较抽象的类型在参数上;泛型不能协变就会限制使用,因为有些类型会写不出合适的抽象类型。 例如java.util.Collections类上有sort方法: public static <T> void sort(List<T> list, Comparator<? super T> c) 这个方法的第二个参数是Comparator<? super T>类型的。为什么不能是Comparator<T>呢? 假如我们手上有一个Comparator<Object>,是通用的,那它本来应该可以用来比较任意引用类型的对象;但Comparator<Object>不是任意Comparator<T>的子类型,所以无法传递给一个Comparator<T>的参数。 而Comparator<? super T>则用于表示逆变(contravariance);这个类型是任意Comparator<U>的父类型,只要T是U的子类型。 所以Collections.sort()按现有的方式声明,我们就做到: Comparator<Object> c = ...; List<String> list = ...; Collections.sort(list, c); 类似的,extends用于表示协变(covariance)。不带有super/extends的泛型类型不参与协变/逆变,这点理解了就完成了第一步。PECS则能帮助你理解第二步:到底协变跟逆变的“方向”是什么意思。 多废话无益,请先读了Effective Java第二版的Item 28再说。 |
|
返回顶楼 | |
发表时间:2012-02-14
suigara 写道 帖子很好 至少学会了两个名词 协变和逆变
虽然看了定义发现以前也知道那么回事。。。。。 java的数组确实是协变的,泛型应该不是吧 List<String>不能赋值给List<Object>变量 泛型应该是不可变的吧,起码应该不支持declaration-site variance的吧。 嗯我前面说错了。Java是不支持declaration-site variance的。只支持use-site variance。 |
|
返回顶楼 | |
发表时间:2012-02-14
RednaxelaFX 写道 amoszhou 写道 RednaxelaFX 写道 amoszhou 写道 RednaxelaFX 写道 楼主需要的是PECS口诀。《Effective Java》第二版原文版的136页。
大神,这个还真不是需要口诀。 如果只是背口诀我就不用来问了。 口诀是为了帮助记忆用的。很明显你没理解Java泛型里covariance(协变)和contravariance(逆变)的特性的影响。PECS口诀正是帮助记忆这个用的。当然,肯不肯去看是你自己决定的事情咯 顺带一提,Java泛型的variance是同时支持use-site variance和declaration-site variance的。而正是use-site variance让楼主头疼了。后来C#支持variance的时候就没用这么复杂的设计,而是只支持declaration-site variance,就没这种问题。反正就是语言设计中的各种取舍。 如果对背景完全没了解可以找些问答帖看,例如这个:http://stackoverflow.com/questions/4231305/how-does-javas-use-site-variance-compare-to-cs-declaration-site-variance 别外,大神看下IBM的这篇文章: http://www.ibm.com/developerworks/cn/java/j-jtp04298.html 里面有这么一句话: 通配符在类型系统中的作用部分来自其不会发生协变(covariant)这一特性。数组是协变的,因为 Integer 是 Number 的子类型,数组类型 Integer[] 是 Number[] 的子类型,因此在任何需要 Number[] 值的地方都可以提供一个 Integer[] 值。另一方面,泛型不是协变的, 作者说泛型不是协变的。。那不是和你说的冲突了? 你或许太性急了,先冷静下来整理一下你已经理解的 现成的讲解太多了,本来懒得增添杂音… 在Java里,不带super和extends的泛型是不协变的。所以,如果有: public interface List<E> { } public class Fruit { } public class Apple extends Fruit { } 那么Apple是Fruit的子类型,但List<Apple>不是List<Fruit>的子类型。这里体现了泛型的不协变性。 但是这样有时候会很尴尬。如果要写一个通用的方法,本来可以放个较抽象的类型在参数上;泛型不能协变就会限制使用,因为有些类型会写不出合适的抽象类型。 例如java.util.Collections类上有sort方法: public static <T> void sort(List<T> list, Comparator<? super T> c) 这个方法的第二个参数是Comparator<? super T>类型的。为什么不能是Comparator<T>呢? 假如我们手上有一个Comparator<Object>,是通用的,那它本来应该可以用来比较任意引用类型的对象;但Comparator<Object>不是任意Comparator<T>的子类型,所以无法传递给一个Comparator<T>的参数。 而Comparator<? super T>则用于表示逆变(contravariance);这个类型是任意Comparator<U>的父类型,只要T是U的子类型。 所以Collections.sort()按现有的方式声明,我们就做到: Comparator<Object> c = ...; List<String> list = ...; Collections.sort(list, c); 类似的,extends用于表示协变(covariance)。不带有super/extends的泛型类型不参与协变/逆变,这点理解了就完成了第一步。PECS则能帮助你理解第二步:到底协变跟逆变的“方向”是什么意思。 多废话无益,请先读了Effective Java第二版的Item 28再说。 学习了 现成的讲解确实很多,但能深入、全面讲解的基本上都是英文的 看起来太累。。。。 |
|
返回顶楼 | |
发表时间:2012-02-14
RednaxelaFX 写道 suigara 写道 帖子很好 至少学会了两个名词 协变和逆变
虽然看了定义发现以前也知道那么回事。。。。。 java的数组确实是协变的,泛型应该不是吧 List<String>不能赋值给List<Object>变量 泛型应该是不可变的吧,起码应该不支持declaration-site variance的吧。 嗯我前面说错了。Java是不支持declaration-site variance的。只支持use-site variance。 恩 多谢解答 |
|
返回顶楼 | |
发表时间:2012-02-14
最后修改:2012-02-14
另外 看了RednaxelaFX的回答 还有人会投隐藏么??
还有 百度已经能搜到这个帖子了。。。。 搜索use-site variance 第一个中文帖子就是。。。。 RednaxelaFX有空普及一下这些名词吧 看英文的太累。。。。 |
|
返回顶楼 | |
发表时间:2012-02-14
是啊。同楼上,RednaxelaFX科普一下吧。
关于use-site variance 以及 declaration-site variance 吧。 这种讨论贴都有人投隐藏贴,不知道是何方大神 |
|
返回顶楼 | |
发表时间:2012-02-15
RednaxelaFX今天还没出现?
|
|
返回顶楼 | |