“未选中的分配”警告

我使用的是 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();
    }
}

但要通用:A

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

还有这行:

Map<Integer, String> map = a.getMap();

现在收到警告:."Unchecked assignment: 'java.util.Map to java.util.Map<java.lang.Integer, java.lang.String>'

即使 的签名完全独立于 ,并且代码对于所包含的类型是明确的。getMapTMap

我知道我可以通过按如下方式重新实现来摆脱警告:processA

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

但是,我为什么要这样做呢?这里有什么关系呢?T

所以,问题是 - 为什么类型擦除不仅要影响(这是可以理解的 - 如果我传递的实例,是未知的),而且还要像在这种情况下那样“硬编码”通用签名?TAT<Integer, String>


答案 1

在第二种情况下,当您执行以下操作时:

public void processA(A a)

你这是什么意思?它的意思是还是什么?您可能没有使用与 类型相关的任何内容,但嘿,编译器不知道这个事实。对于编译器来说,只是恐慌的标志。AA<String>A<List<String>>AA

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

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

具有均值的参数类型,您并不特别关心的类型,而只是指定通配符。对您来说,它的意思是:任何具有任何类型的对象,就像其泛型类型一样。实际上,这意味着您不知道类型。它无用,因为你不能以类型安全的方式做任何与之相关的事情,因为几乎可以做任何事情!A<?>AAA?

但是根据你的方法体,它在世界上使用是有意义的,因为在身体的任何地方你实际上不需要的类型A<?>A


答案 2

当您打算接受任何可能类型的 a,但不需要 时,通过使用通配符和写入 来正确表示。这样做将消除代码中的警告:A<T>TTA<?>

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

使用裸类型不会得到等效处理。如 Java 语言规范中所述,此类原始类型不适合在新代码中使用:A

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

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


推荐