简体   繁体   English

在方法参数中使用通配符

[英]Using wildcard in method argument

I have declared a method whose argument is subtype of Number as given below: 我已经声明了一个方法,其参数是Number子类型,如下所示:

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

I am able to pass any non-parameterized lists as argument. 我可以将任何非参数化列表作为参数传递。 So what is the point of using wildcard <? extends Number> 那么使用通配符<? extends Number> <? extends Number> ? <? extends Number>

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

Why do I get element of type Object from c ? 为什么我从c获取Object类型的元素? And not of type Number ? 而不是Number类型? Is there a way to allow only subtypes of a type to be passed as arguments as opposed to allowing non-parameterized arguments also? 有没有办法只允许一种类型的子类型作为参数传递,而不允许非参数化的参数呢?

You are asking three questions here, I will answer them separately. 你在这里问三个问题,我将分别回答。 By the way, you would find it valuable to read the Java Generics FAQ - considered by many to be the canonical reference on the subject : 顺便说一下,你会发现阅读Java Generics FAQ很有价值- 被许多人认为是关于这个主题的规范参考

  1. So what is the point of using wildcard <? extends Number> 那么使用通配符<? extends Number> <? extends Number> ? <? extends Number>

You need to use the wildcard for the times when the parameterized argument is a subclass of Number , say, Integer . 当参数化参数是Number的子类(例如, Integer时,您需要使用通配符。 For instance: 例如:

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) {

    }
}

The second method call fails with the compilation error: 第二个方法调用因编译错误而失败:

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

  1. Why do I get element of type Object from c ? 为什么我从c获取Object类型的元素? And not of type Number ? 而不是Number类型?

The reason you get a type of Object in your second case is because you are using the Raw Type. 在第二种情况下获得一种Object类型的原因是因为您使用的是Raw Type。 You should never use a raw type if you can avoid it for that reason - you lose all the advantages of compiler type checking. 如果由于这个原因可以避免使用原始类型,则永远不应该使用原始类型 - 您将失去编译器类型检查的所有优点。


  1. Is there a way to allow only subtypes of a type to be passed as arguments as opposed to allowing non-parameterized arguments also? 有没有办法只允许一种类型的子类型作为参数传递,而不允许非参数化的参数呢?

You cannot prevent Heap Pollution in the way you describe because someone can always cast to the Raw type and then to whatever is required. 您不能以您描述的方式阻止堆污染 ,因为有人总是可以转换为Raw类型,然后转换为所需的任何内容。 Generics are a compile time only construct, and are ultimately erased after compilation. 泛型是仅编译时构造,并且在编译后最终被擦除。 This is why the Unchecked Type Conversion warning can only be suppressed via annotation. 这就是为什么只能通过注释来抑制未选中类型转换警告的原因。

You must remember that in Java generics are a compile-time construct to help with type-safety. 您必须记住,Java泛型是一个编译时构造,以帮助进行类型安全。 At run-time, type erasure converts all generic types to Object and add casting where required. 在运行时,类型擦除会将所有泛型类型转换为Object并在需要时添加转换。 If you bypass the compile-time checking by using raw types (for which the compiler gives you a warning) you have bypassed the benefit of generics (compile-time type checking and run-time safe casting). 如果通过使用原始类型(编译器为其提供警告)绕过编译时检查,则绕过了泛型的好处(编译时类型检查和运行时安全转换)。

Generics in Java are implemented via Type erasure. Java中的泛型是通过Type erasure实现的。 ie: type information that you specify in <> do not exist during runtime. ie:您在<>中指定的类型信息在运行时期间不存在。 During compile time the java compiler makes use of the information given in <> to make sure that everything is in order. 在编译期间,java编译器利用<>中给出的信息来确保一切都井然有序。 If however you do not specify the type in <> as you have done for the variable 'newList' nothing prevents you from passing it to the 'organizeData' method. 但是,如果您没有在变量'newList'中指定<>中的类型,则无法阻止您将其传递给'organizeData'方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM