论坛首页 Java企业应用论坛

关于Java泛型 与 类型推断

浏览 21827 次
精华帖 (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>列??  
0 请登录后投票
   发表时间:2012-02-14  
RednaxelaFX 写道
楼主需要的是PECS口诀。《Effective Java》第二版原文版的136页。



大神,这个还真不是需要口诀。 如果只是背口诀我就不用来问了。
0 请登录后投票
   发表时间:2012-02-14  
PECS口诀是什么?好早以前看过Effective Java,没记得有个叫PECS的东东呀。
0 请登录后投票
   发表时间: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
0 请登录后投票
   发表时间: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());
0 请登录后投票
   发表时间: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);
所以你说的那种编码是有问题的,子类型限定一般不用来设置泛型对象.
0 请登录后投票
   发表时间: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那些天书比,显然不是一个级别的
0 请登录后投票
   发表时间:2012-02-14  
RednaxelaFX 写道
楼主需要的是PECS口诀。《Effective Java》第二版原文版的136页。

+1
这里有个简单的解释:http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs
简单的说:
使用 ? extends 通配符,用于获取数据
使用 ? super 通配符,用于写入数据

0 请登录后投票
   发表时间:2012-02-14  
ol_beta 写道
RednaxelaFX 写道
楼主需要的是PECS口诀。《Effective Java》第二版原文版的136页。

+1
这里有个简单的解释:http://stackoverflow.com/questions/2723397/java-generics-what-is-pecs
简单的说:
使用 ? extends 通配符,用于获取数据
使用 ? super 通配符,用于写入数据


正解。
0 请登录后投票
   发表时间: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(逆变)。在网上搜到很多资料都不是太有用,本人英文水平又不是太好,所以。。。
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics