泛型<T>的转换问题

问答里提问,没有得到答案,特开此贴讨论。
代码如下:


public class Cast {
public static &lt;T&gt; T cast(Object o){  
    return (T)o;  
}  

public static void main(String[] args){  
        Object o =new Bird();  
        Bird b=Cast.cast(o);  //cast方法上的Doc提示:&lt;Bird&gt; Bird Cast.cast(Object o)
        Cast.cast(o); //Doc提示: &lt;Object&gt; Object Cast.cast(Object o) 

        Fish f=Cast.cast(b); //Doc提示:&lt;Fish&gt; Fish Cast.cast(Object o) //!!ClassCastException
}  

public static class Bird{} 
public static class Fish{} 

}



cast泛型方法是如何做类型推断的?
Bird b=Cast.cast(o); //cast如何推断出T就是Bird??!! 问题在这里
Cast.cast(o); //cast此时只能推断出T就是Object

难道区别在于有没有接收返回值,有的话,可以根据"="号左边的类型继续推断;没有的话,只能推断出cast方法的参数类型;

求详细解答 或 给予参考资料 OTZ


问题补充
七心JAVA 写道
Bird b=Cast.cast(o);
是不是得加个类型强制转换?

不需要,代码是从eclipse里拿出来的,java编译器可以通过
问题补充
IcyFenix 写道
嗯,实际上这里确实是有个强制转换的,只不过...

恩,请详细解释: Bird b=Cast.cast(o); //cast如何推断出T就是Bird??!! 问题在这里

所有的泛型信息都会被擦除掉,这么说绝对吗?

LZ可参考一下这贴:http://www.iteye.com/topic/1021949

单独一份讲泛型的资料应该无法全面说明你所问的问题,你这个问题的关键不在泛型,而在于编译器解语法糖时的泛型擦除过程。所以还需要讲一下javac(你这里实际上是ecj)是如何解语法糖的,但是那个太长了,贴出来不太方便,LZ先看看这个吧。

Bird b=Cast.cast(o);
是不是得加个类型强制转换?

嗯,实际上这里确实是有个强制转换的,只不过不需要你自己手动去加,编译器在解语法糖的时候自动帮你添加了。

main方法在解语法糖之后,实际上是这样的:
[code="java"] public static void main(String[] args) {
Object o = new Cast.Bird();
Cast.Bird b = (Cast.Bird)cast(o);

cast(o);

Cast.Fish f = (Cast.Fish)cast(b);

}[/code]

而cast的方法描述符和(字节码级的)方法签名是这样的:
// Method descriptor #15 (Ljava/lang/Object;)Ljava/lang/Object;
// Signature: (Ljava/lang/Object;)TT;
请注意,Method descriptor中,方法返回值就是Ljava/lang/Object而已,泛型被擦除掉了。

至于你要的资料,我整理一下发一篇出来吧。

[quote="mwei"]难道区别在于有没有接收返回值,有的话,可以根据"="号左边的类型继续推断;没有的话,只能推断出cast方法的参数类型;[/quote]
正是如此。在Java语言规范里有规定:
[url=http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.2.8]15.12.2.8 Inferring Unresolved Type Arguments[/url]
不只是等号赋值,作为参数传递的情况也算“赋值”因而也一样会用于推导。