为什么超级类通用类型没有被擦除/转换

时间:2016-04-07 06:05:56

标签: java generics

考虑以下代码:

class A<T>{
T t;

public T getValue(){
    return t;
}

class B<S extends Number> extends A<String>{

//some code here..
}

B b = new B<Integer>();
String name = b.getValue() // This throws compilation error

而以下工作:

B<Integer> b = new B<Integer>();
String name = b.getValue() // This works...!

所以我的问题是:

  1. 我是否必须声明所涉及的所有泛型类型? (尽管A类的通用类型是在B类中宣布的。)

  2. 或者,我基本上错过了什么?

2 个答案:

答案 0 :(得分:3)

请参阅JLS 4.8 Raw Types

  

原始类型被定义为通过获取泛型类型声明的名称而不带伴随类型参数列表而形成的引用类型。

     

原始类型的超类(分别是超级接口)是其任何参数化调用的超类(超接口)的擦除。

换句话说,当你使用B而没有<>时,它会变成一个原始类型,基本上删除所有泛型,一直到所有基类和接口, ie就好像AB不是通用的:

class A {
    Object t;
    public Object getValue() {
        return t;
    }
}

class B extends A {
    //some code here..
}

String name = b.getValue()失败的原因是什么,因为getValue()现在正在返回Object

请注意JLS中的以下注释:

  

原始类型的使用仅允许作为遗留代码兼容性的让步。 强烈建议不要在将泛型引入Java编程语言后编写的代码中使用原始类型 。未来版本的Java编程语言可能会禁止使用原始类型。

简而言之,不要。修复您的代码不使用原始类型。

但您可以按如下方式缩短右侧:

B<Integer> b = new B<>();

答案 1 :(得分:-1)

B类的通用值与A类的通用值无关。

A(Long)的方法T getValue()将是Long getValue(),忽略包装类的任何通用性。

如果你想要一个Integer getValue(),那么只需转到

class B extends A<Integer> {}

编辑:你改变了你的问题,让我们改变回应:)

B被认为是B(S扩展数,T)(因为它扩展了A)。 如果将变量存储为原始类型B,则它隐式为B(对象,对象),即使声明正确。

使用列表进行测试

List l = new ArrayList<String>();
String s = l.get(0);

你将以同样的问题结束。