2014-10-08 59 views
5

使用通配符我宣布下面给出其参数是Number型的方法:在方法参数

public static void organizeData(java.util.List<? extends Number> c) { 
    //operation on the list 
} 

我能够通过任何非参数列表作为参数。那么使用通配符<? extends Number>有什么意义?

List newList = new LinkedList<>(); 
ClassName.organizeData(newList); 

为什么我从c得到Object类型的元素?而不是类型Number?有没有办法只允许一个类型的子类型作为参数传递,而不是允许非参数化的参数呢?

+5

你不能阻止。用户总是可以首先投射到原始类型,然后投射到任何需要的地方。泛型有其局限性,原始类型总是打破它们。 – 2014-10-08 13:35:13

回答

6

你在这里问三个问题,我会单独回答。顺便问一下,你会发现非常值得阅读Java Generics FAQ - considered by many to be the canonical reference on the subject

  1. 那么,什么是使用通配符<? extends Number>点?

您需要使用通配符的时候,参数化的参数是Number,比方说,Integer一个子类。例如:

import java.util.LinkedList; 
import java.util.List; 

public class NumberTest { 
    public static void main(String... args) { 
     List<Integer> newList = new LinkedList<Integer>(); 
     organizeData(newList); // This works! 
     anotherMethod(newList); // Doesn't compile 
    } 

    private static void organizeData(List<? extends Number> list) { 

    } 

    private static void anotherMethod(List<Number> list) { 

    } 
} 

第二种方法调用失败,编译错误:

NumberTest.java:9: error: method anotherMethod in class NumberTest cannot be applied to given types; 
         anotherMethod(newList); // Doesn't compile 
         ^
    required: List<Number> 
    found: List<Integer> 
    reason: actual argument List<Integer> cannot be converted to List<Number> by method invocation conversion 
1 error 

  • 为何我从c得到Object型的元件?而不是类型Number
  • 您在第二种情况下得到一个类型的Object的原因是因为you are using the Raw Type.你不应该使用原始类型,如果你能避免它出于这个原因 - 你失去编译器的类型检查的所有优点。


  • 有一种方法以允许相对于允许非参数化的参数也仅一个类型的子类型作为参数传递?
  • 您不能防止Heap Pollution在你的描述,因为有人可以随时转换为原始类型,然后到任何需要的方式。泛型只是一个编译时构造,并且are ultimately erased after compilation.这就是为什么未检查类型转换警告只能通过注释来抑制。

    1

    您必须记住,在Java中,泛型是编译时构造以帮助实现类型安全。在运行时,类型擦除将所有通用类型转换为Object,并在需要时添加铸件。如果绕过使用原始类型(编译器给出警告)的编译时检查,则绕过了泛型的好处(编译时类型检查和运行时安全转换)。

    0

    Java中的泛型通过类型擦除来实现。一世。e:在运行时不存在您在<>中指定的类型信息。在编译期间,java编译器利用<>中给出的信息来确保所有内容都按顺序排列。但是,如果您没有在变量'newList'中指定<>中的类型,则不会阻止将它传递给'organizationalData'方法。