Java 是否允许在实例化期间使用通配符

Java 是否允许在实例化期间使用通配符,java,generics,wildcard,Java,Generics,Wildcard,为什么这些声明在Java中无效 List test=new ArrayList这不是有效的声明,因为它不是已知的类型。这里没有指定完整类型new ArrayList可以接受任何通过子类型扩展的Number,以便您使用?扩展Foo不是有效的需求 列表可以接受整数、长等。没有办法做与等价的事情?super Foo因为它在语义上除了列表或列表之外没有任何意义,并且有一个奇怪的人为限制。您当前的定义不正确,泛型类型应该在两侧相同,或者应该具有继承关系。通配符的意思是“未知”而不是“任何”。实例化一个包含

为什么这些声明在Java中无效


  • List test=new ArrayList这不是有效的声明,因为它不是已知的类型。这里没有指定完整类型
    new ArrayList
    可以接受任何通过子类型扩展的
    Number
    ,以便您使用
    ?扩展Foo
    不是有效的需求


    列表
    可以接受
    整数
    等。没有办法做与
    等价的事情?super Foo
    因为它在语义上除了
    列表
    列表
    之外没有任何意义,并且有一个奇怪的人为限制。

    您当前的定义不正确,泛型类型应该在两侧相同,或者应该具有继承关系。

    通配符的意思是“未知”而不是“任何”。实例化一个包含未知内容的新容器没有任何意义,您会在其中放入什么?它真的不能用于任何事情


    因此,声明
    newarraylist不会被Java继承概念和Java泛型概念的通配符(例如这里的通配符)语法混淆。两者都不相同,并且没有一条继承规则适用于java泛型概念

    因此,
    编号
    不同?扩展号码

    请注意,Java通用通配符旨在告诉编译器有关对象的预期用途。在运行时,它根本不存在


    如果您认为java中的泛型只是一种防止犯错误的工具,那么在理解这个概念时就不应该出错。

    java泛型不是协变的。例如,见Brian Goetz的文章。您的第一个示例有两个问题。首先,当您实例化一个类型时,必须完全指定它(包括任何类型参数)。其次,类型参数必须与左侧完全匹配

    关于类型协方差(或缺乏协方差),这也是不合法的:

    List<Number> test = new ArrayList<Integer>();
    
    因为泛型不是协变的,所以它再次失败

    至于为什么必须完全指定类型参数,说明了这一概念:

    泛型类声明定义了一组参数化类型(§4.5),每个类型参数节的类型参数调用一个

    您只能实例化实际的类型。只要泛型类型的类型参数未绑定,泛型类型本身就是不完整的。您需要告诉编译器正在实例化哪个特定的参数化类型(在泛型类定义的集合中)

    至于泛型为何不协变,这是为了防止以下类型的错误:

    List<Integer> iTest = new ArrayList<Integer>();
    List<Number> test = iTest;
    test.add(Double.valueOf(2.5));
    Integer foo = iTest.get(0); // Oops!
    
    List iTest=new ArrayList();
    列表测试=iTest;
    试验添加(双值(2.5));
    整数foo=iTest.get(0);//哎呀!
    
    要理解为什么不允许创建通配符参数化类型的对象,必须首先了解通配符参数化类型的用途

    为什么是通配符? 正如您已经知道的,Java泛型是不变的。因此,
    列表
    不是
    列表
    的超类,即使它们的类型参数是协变的。那么,如果您也希望在泛型中有这样的行为,比如相同的引用指向不同的对象,该怎么办?就像你所说的那样,那是多态的东西。如果您想要一个
    列表
    引用来引用
    整数
    浮点
    列表,该怎么办

    通配符用于救援:
    使用通配符,可以实现上述行为。因此,
    List在实例化参数化类时,参数必须是某种已知的具体类型。即使使用
    也可以将其参数化为类,但出于推理原因,它必须是具体的。例如,这是一个有效的声明:
    new arraylisty您不能实例化您不知道的类型。右侧需要是具体的。通过多态性扩展的
    Number
    类型是否正确?因此,可以添加到
    列表中的内容将是类型为
    ListNo,
    ?扩展数字
    意味着“此列表包含一个数字的精确子类型,可能是整数,可能是浮点,无论什么,但我不知道是哪一个”因此您不能添加任何内容,因为您刚刚告诉它您不知道列表中已经有哪个子类型!所以它意味着只包含一个数字的子类型,我想我可以混合使用不同的子类型,比如整数,双etcA列表,可以包含任何数字的子类型,它只是一个
    列表
    !通配符是“未知”而不是“任何”。那么为什么允许这样做:
    List>()?您能否详细说明这些规则如何不适用?当我们说
    ?扩展数字
    ,它的意思是“这是数字的一个确切的子类型,但我不知道是哪一个”,正如下面的一条评论所提到的。因此
    ?extends Number
    必须是
    Number
    的子类型,这是多态性(不是特别的继承),您可能需要阅读Tedd Hopp提供的链接以了解更多信息。一个这样的例子是generic没有类似于covarient赋值的东西。仅仅因为泛型的一些语法看起来像是天生的,并不意味着它支持多态性和继承特性。现在,如果你问为什么会给出这样的语法,那就是在运行时支持为多态行为编写的代码;但对于多态泛型概念来说是不可能的。实际上OP似乎知道泛型不变性。他很想知道为什么他不能创建通配符参数化类型的对象。@RohitJain-我想OP会的,尽管OP可能不知道这在这里有什么关系。我在回答中还添加了一点关于尝试实例化不完全指定的类型的内容?那么为什么允许这样做:
    列表>()?这似乎比其他答案更接近,但仍然不太正确
    
    List<Object> test = new ArrayList<Integer>();
    
    List<Integer> iTest = new ArrayList<Integer>();
    List<Number> test = iTest;
    test.add(Double.valueOf(2.5));
    Integer foo = iTest.get(0); // Oops!
    
    List<? extends Number> numbers = new ArrayList<Integer>();
    numbers = new ArrayList<Double>();
    numbers = new ArrayList<Float>();
    numbers = new ArrayList<String>();  // This is still not valid (you know why)
    
    // Compiler sees that this method can take List of any subtype of Number
    public void print(List<? extends Number> numbers) {
        // print numbers
    }
    
    public void fillUp(List<? super T> param)