锁定老帖子 主题:关于Java泛型 与 类型推断
精华帖 (0) :: 良好帖 (3) :: 新手帖 (1) :: 隐藏帖 (12)
|
|
---|---|
作者 | 正文 |
发表时间:2012-02-14
黎明的曙光 写道 public void foo(Object o)
public void foo(String str) 这里叫重载解析,不关泛型的事 通配符类型List<? extends Fruit>可以表示两种泛型 List<Fruit>和List<Apple>,那么你怎么确定 List<? extends Fruit>具体表示什么类型呢, 你只有确定类型以后你才能添加那个类型的对象吧,你现在连类型都不确定怎么添加? 假如是表示List<Apple>,后面对其调用add(new Fruit());岂不是很危险? 你自己当然知道它的实际类型应该是Fruit,因为那是你写的阿,假如你这两行代码隔了几百行,你让编译器怎么去找你之前的定义的类型,假如你想用父类List,直接声明一个List<Fruit>不就好了 public void foo(Object o) public void foo(String str) 这里叫重载解析,不关泛型的事 ---这确实是不关泛型的,但是关乎类型推断的事。调用的时候,会找一个最符合的方法去执行。 通配符类型List<? extends Fruit>可以表示两种泛型 List<Fruit>和List<Apple>,那么你怎么确定 因为List<Fruit> fruits = apples是不成立的。 所以 List<? extends Fruit> fruits = apples的时候, 编译是不是应该可以推断List<? extends Fruit>的类型为List<Apple>列?? |
|
返回顶楼 | |
发表时间:2012-02-14
RednaxelaFX 写道 楼主需要的是PECS口诀。《Effective Java》第二版原文版的136页。
大神,这个还真不是需要口诀。 如果只是背口诀我就不用来问了。 |
|
返回顶楼 | |
发表时间:2012-02-14
PECS口诀是什么?好早以前看过Effective Java,没记得有个叫PECS的东东呀。
|
|
返回顶楼 | |
发表时间:2012-02-14
最后修改:2012-02-14
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 |
|
返回顶楼 | |
发表时间:2012-02-14
黎明的曙光 写道 xiaoZ5919 写道 shbgreenery 写道 List<? super Fruit> list = new ArrayList<Apple>();
list.add(new Apple()); list.add(new Fruit()); 这段代码在eclipse3.7上编译不通过,你是用什么编译器呢 因为代码有错 是写得有问题 List<? super Fruit> fruits = new ArrayList(); fruits.add(new Apple()); fruits.add(new Fruit()); |
|
返回顶楼 | |
发表时间:2012-02-14
amoszhou 写道 黎明的曙光 写道 public void foo(Object o)
public void foo(String str) 这里叫重载解析,不关泛型的事 通配符类型List<? extends Fruit>可以表示两种泛型 List<Fruit>和List<Apple>,那么你怎么确定 List<? extends Fruit>具体表示什么类型呢, 你只有确定类型以后你才能添加那个类型的对象吧,你现在连类型都不确定怎么添加? 假如是表示List<Apple>,后面对其调用add(new Fruit());岂不是很危险? 你自己当然知道它的实际类型应该是Fruit,因为那是你写的阿,假如你这两行代码隔了几百行,你让编译器怎么去找你之前的定义的类型,假如你想用父类List,直接声明一个List<Fruit>不就好了 public void foo(Object o) public void foo(String str) 这里叫重载解析,不关泛型的事 ---这确实是不关泛型的,但是关乎类型推断的事。调用的时候,会找一个最符合的方法去执行。 通配符类型List<? extends Fruit>可以表示两种泛型 List<Fruit>和List<Apple>,那么你怎么确定 因为List<Fruit> fruits = apples是不成立的。 所以 List<? extends Fruit> fruits = apples的时候, 编译是不是应该可以推断List<? extends Fruit>的类型为List<Apple>列?? 就是因为List<? extends Fruit> fruits它可以是List<Apple>又可以是List<Fruit>,所以它推断不了它的通配符类型到底是哪种类型的,所以一般带有子类型限定也就是extends的不用来设置泛型对象,就好比你这里的 List<? extends Fruit> fruits不能用来添加元素,子类型限定的通配符类型一般只用来获取泛型对象,比如在从fruits中获取某个索引处的对象,用: Fruit f = fruits.get(2); 所以你说的那种编码是有问题的,子类型限定一般不用来设置泛型对象. |
|
返回顶楼 | |
发表时间:2012-02-14
黎明的曙光 写道 amoszhou 写道 黎明的曙光 写道 public void foo(Object o)
public void foo(String str) 这里叫重载解析,不关泛型的事 通配符类型List<? extends Fruit>可以表示两种泛型 List<Fruit>和List<Apple>,那么你怎么确定 List<? extends Fruit>具体表示什么类型呢, 你只有确定类型以后你才能添加那个类型的对象吧,你现在连类型都不确定怎么添加? 假如是表示List<Apple>,后面对其调用add(new Fruit());岂不是很危险? 你自己当然知道它的实际类型应该是Fruit,因为那是你写的阿,假如你这两行代码隔了几百行,你让编译器怎么去找你之前的定义的类型,假如你想用父类List,直接声明一个List<Fruit>不就好了 public void foo(Object o) public void foo(String str) 这里叫重载解析,不关泛型的事 ---这确实是不关泛型的,但是关乎类型推断的事。调用的时候,会找一个最符合的方法去执行。 通配符类型List<? extends Fruit>可以表示两种泛型 List<Fruit>和List<Apple>,那么你怎么确定 因为List<Fruit> fruits = apples是不成立的。 所以 List<? extends Fruit> fruits = apples的时候, 编译是不是应该可以推断List<? extends Fruit>的类型为List<Apple>列?? 就是因为List<? extends Fruit> fruits它可以是List<Apple>又可以是List<Fruit>,所以它推断不了它的通配符类型到底是哪种类型的,所以一般带有子类型限定也就是extends的不用来设置泛型对象,就好比你这里的 List<? extends Fruit> fruits不能用来添加元素,子类型限定的通配符类型一般只用来获取泛型对象,比如在从fruits中获取某个索引处的对象,用: Fruit f = fruits.get(2); 所以你说的那种编码是有问题的,子类型限定一般不用来设置泛型对象. 这不是推断不了,而是java不做,这里和c++template那些天书比,显然不是一个级别的 |
|
返回顶楼 | |
发表时间:2012-02-14
RednaxelaFX 写道 楼主需要的是PECS口诀。《Effective Java》第二版原文版的136页。
+1 这里有个简单的解释:http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs 简单的说: 使用 ? extends 通配符,用于获取数据 使用 ? super 通配符,用于写入数据 |
|
返回顶楼 | |
发表时间:2012-02-14
ol_beta 写道 RednaxelaFX 写道 楼主需要的是PECS口诀。《Effective Java》第二版原文版的136页。
+1 这里有个简单的解释:http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs 简单的说: 使用 ? extends 通配符,用于获取数据 使用 ? super 通配符,用于写入数据 正解。 |
|
返回顶楼 | |
发表时间: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 求大神讲一下: covariance(协变)和contravariance(逆变)。在网上搜到很多资料都不是太有用,本人英文水平又不是太好,所以。。。 |
|
返回顶楼 | |