2015-03-02 43 views
19

我正在使用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>'

尽管getMap的签名完全独立于T,并且该代码对于包含Map的类型是明确的。

我知道我可以通过重新实现processA如下摆脱了警告:

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

但我干嘛要这么做? T这里有什么关系?

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

回答

13

在你的第二个情况下,当你这样做:

public void processA(A a) 

你说的A是什么意思?这是否意味着A<String>A<List<String>>还是什么?你可能没有使用任何与A类型相关的东西,但是嘿编译器不知道这个事实。编译器,只是A是恐慌的标志。

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

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

具有A<?>方法的参数类型,你不特别关心的A类型仅仅指定一张通配符。对你而言意味着:A的任何对象都可以作为其泛型类型。实际上,这意味着你不知道类型。它无用,因为你不能以类型安全的方式做任何与A有关的事情,因为?几乎可以成为任何东西!

但按你的方法体,它使世界上所有的有意义的使用A<?>因为在身体任何地方你的实际需要'你可能没有使用与A型的东西的A

+0

类型,但是嘿编译器不知道这个事实 - 好吧,它可以很容易地知道它,只要看一下'processA'的实现,不难验证'T'是不相关的; )按照你的建议,我会用''去,但是我对编译器感到失望。 – 2015-03-02 12:10:36

+0

@KonradMorawski在理想的世界里,只有'A'应该是非法的,代码不应该被编译。但是出于向后兼容的原因,这是允许的。对于声明为“A ”的类,其泛型类型对于执行与“A”相关的任何操作都非常重要。因此,不应该允许使用'A'(实际上在Scala中,仅仅使用'A'是非法的) – Jatin 2015-03-02 12:17:21

+0

是的,我想......我不使用Scala,但是我来自C#端的世界和Java的泛型感觉就像穿着太小的鞋子一样。 – 2015-03-02 12:23:10

5

当你的意思是接受任何可能的类型TA<T>,但不需要T,这是正确使用通配符和写作A<?>表示。这样做将摆脱警告在代码:

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

使用裸型A不等同对待。正如在Java Language Specification说明的,原始类型,如不打算在新代码中使用:

未经检查的转换用于启用的传统代码的平滑互操作,引入一般类型的之前写入,与库,已经经历了转换,以使用通用性(我们称之为“基因化”的过程)。在这种情况下(最着名的是java.util中Collections Framework的客户端),传统代码使用原始类型(例如Collection而不是Collection <String>)。原始类型的表达式作为参数传递给库方法,这些方法使用这些相同类型的参数化版本作为其相应形式参数的类型。

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