2016-02-12 76 views
7

我们已经开始收到编译所使用泛型的代码错误和Java的6下成功编译Java的泛型编译时错误这里有一个简单的类重现:迁移从Java 6到7或8

class Test { 
    static class Foo<T> { 
      T t; 
      Foo(T t) { this.t = t; } 
      T get() { return t; } 
    } 

    static class Bar extends Foo<Long> { 
      Bar(Long t) { super(t); } 
    } 

    static class Foobar<N extends Number> extends Bar { 
      Foobar() { super(5L); } 
    } 

    public static void main(String[] args) { 
      Bar bar = new Bar(0L); 
      Long b = bar.get();    // This works 
      Foobar foobar = new Foobar(); 
      Long fb = foobar.get(); // This generates a compile time error 
    } 
} 

由此产生的错误是:

Test.java:26: error: incompatible types: Object cannot be converted to Long 
      Long fb = foobar.get(); // This generates a compile time error 

有没有人有任何想法?

+0

对不起,没有提到编译错误发生在Java 7和8中,但不是在6 ... –

+0

奇怪的是,虽然我从命令行使用jdk1.7.0_13得到这个编译错误,但这段代码编译得很好在eclipse中,使用相同的编译器(双重检查“已安装的JRE”指向相同的路径,合规性级别为1.7,并使用该jdk)。 – azurefrog

+0

我得到了完全一样的 - Eclipse编译1.8集没有错误。很奇怪...... –

回答

2

这是因为Foobar没有任何类型参数是原始类型。原始类型没有通用能力,因此在这种情况下,原始类型Foobar延伸了Bar,这扩展了原始类型Foo。原始类型使用其参数的上限,因为它们在擦除之后以这种方式编译,并且编译器没有类型参数来安全地插入强制转换。

Foo的情况下,该上限为Object。这导致Foo.get()返回Object,所以Bar.get()返回Object,所以Foobar.get()也返回Object以及。很明显,编译器不会将Object转换为Long而不显式转换。

相反,参数化类型Foobar<N>延伸Bar,它扩展了参数化类型Foo<Long>。编译器现在可以使用仿制药,所以它看到Foo<T>.get()的类型为T,即Foo<Long>.get()具有类型Long,即Bar.get()具有类型Long,最后是Foobar<N>.get()具有类型Long为好。

这意味着如图所示,你应该申报foobar

Foobar<...> foobar = new Foobar<...>(); 

不要紧的foobar类型参数是什么,就像只要它存在。它甚至可以是通配符?

+2

但是,为什么原始类型在1.6中工作?我不知道1.7中泛型的任何变化(除了类型推断) – radoh

+0

@radoh我认为他们只是在7中进行了更严格的类型检查。原始类型不应该存在于现代代码中,它们仅用于兼容性,类型即使调用代码不是调用泛型更新。尽管并不确定,但最好只检查Oracle的发行说明。 – HTNW

+0

感谢您的解释,就我个人而言,我认为Java 6的方式更直观,所需的更改意味着代码必须更长时间。没有参数定义的泛型类型实例应该被视为基本参数,在这种情况下Foobar本身应该被视为Foobar ... –