未经检查的分配警告

Kon*_*ski 27 java generics unchecked type-erasure raw-types

我使用的是Android Studio 1.1.0.

这不会导致警告:

public static class A {
    public Map<Integer, String> getMap() {
        return null;
    }
}

public static class B {
    public void processA(A a) {
        Map<Integer, String> map = a.getMap();
    }
}
Run Code Online (Sandbox Code Playgroud)

但制作A通用:

public static class A<T> {
    public Map<Integer, String> getMap() {
        return null;
    }
}
Run Code Online (Sandbox Code Playgroud)

这一行:

Map<Integer, String> map = a.getMap();
Run Code Online (Sandbox Code Playgroud)

现在给你一个警告:"Unchecked assignment: 'java.util.Map to java.util.Map<java.lang.Integer, java.lang.String>'.

即使签名getMap完全独立T,并且代码对于Map包含的类型是明确的.

我知道我可以通过重新实现processA如下来消除警告:

public <T> void processA(A<T> a) {
    Map<Integer, String> map = a.getMap();
}
Run Code Online (Sandbox Code Playgroud)

但为什么我必须这样做?T这里有什么关系?

所以,问题是-为什么类型擦除得不仅影响T(这是可以理解的-如果我传递的一个实例A,T是一个未知的),而且还"硬编码"一般签名就像<Integer, String>在这种情况下?

Jat*_*tin 19

在你的第二种情况下:

public void processA(A a)
Run Code Online (Sandbox Code Playgroud)

你什么意思A?这是否意味着A<String>或者A<List<String>>还是什么?您可能没有使用与类型相关的任何内容A,但是编译器不知道这个事实.对于编译器来说,只是A恐慌的表现.

在您的情况下,因为您不需要特别知道A的类型,您可以:

public void processA(A<?> a) {
    Map<Integer, String> map = a.getMap();
} 
Run Code Online (Sandbox Code Playgroud)

有一个参数类型的A<?>均值,你没有特别关心类型,A只是指定一个外卡.对你来说,它意味着:任何A类型的任何类型的泛型类型的对象都可以.实际上,这意味着你不知道这种类型.它没用,因为你无法做任何与A类型安全相关的事情,?几乎可以做任何事情!

但是按照你的方法体,它在世界上的所有意义都可以使用,A<?>因为身体中没有你真正需要的类型A

  • @KonradMorawski 此外,编译器实际上不可能知道它。你可能会进行反思或进行演员阵容并一起工作。显然,很难百分百确信该类型未被使用。 (2认同)
  • @Jatin - 感谢您的回答.这是对我很清楚的通配符的第一个解释.(也许是因为我遇到了提问者的确切问题,我在其中有一个带有显式参数化方法的参数化类,该方法警告在使用时未经检查的赋值.) (2认同)

Dan*_*etz 9

如果您想接受A<T>任何可能的类型T,但不需要T,则可以通过使用通配符和写入来正确表达A<?>.这样做将消除代码中的警告:

public void processA(A<?> a) {
    Map<Integer, String> map = a.getMap();
}
Run Code Online (Sandbox Code Playgroud)

使用裸类型A不会被等效地处理.正如Java语言规范中所解释的那样,这样的原始类型不打算在新代码中使用:

未经检查的转换用于实现在引入泛型类型之前编写的遗留代码与已经过转换以使用泛型的库(我们称之为泛化的过程)的平滑互操作.在这种情况下(最值得注意的是,java.util中的Collections Framework的客户端),遗留代码使用原始类型(例如Collection而不是Collection <String>).原始类型的表达式作为参数传递给库方法,这些库方法使用与其相应形式参数的类型相同类型的参数化版本.

在使用泛型的类型系统下,这样的调用不能显示为静态安全.拒绝此类调用将使大量现有代码无效,并阻止它们使用较新版本的库.反过来,这将阻止图书馆供应商利用通用性.为了防止这种不受欢迎的事件转换,可以将原始类型转换为原始类型引用的泛型类型声明的任意调用.虽然转换是不合理的,但它被视为对实用性的让步.在这种情况下会发出未经检查的警告.