通用方法调用

时间:2015-01-10 15:00:54

标签: java generics

我一直在尝试使用Generic,很快我遇到了一些我无法解释的问题  例如

import java.util.*;
public class Main {
    public static void main(String[] args) {
        //We cannot create List<?> l = new ArrayList<?>();
        List<?> l = MagicClass.factory();
    }
    static class MagicClass {
        public static <T> List<T> factory() {
            return new ArrayList<T>();
        }
    }
}

我不明白<T>如何成为显式类型参数

<?>

未定义。

3 个答案:

答案 0 :(得分:2)

<?>wildcard,它意味着:“您喜欢的任何类型”。现在,由于<?>不对所使用的类型做出任何假设,T只能更多专用。因此,Java将Foo<T>视为Foo<?>。另一方面这样做是不明智的,因为Java没有更少的方法来检查代码。因此,Java通常会拒绝调用任何将type参数用作输入的方法。

  

示例:以下代码无法编译:

    ArrayList<?> foo = new ArrayList<String>();
    foo.add("bar");
     

这是因为,Java不知道T中的foo是什么。 foo可能是ArrayList<Integer>,因此为了安全起见,不允许这样做。

如果您希望例如创建一个可以接受各种List<?>实例的方法,而不管存储在其中的对象,可以使用它。

您永远不能使用通配符构建实例

以下代码无法编译:

ArrayList<?> foo = new ArrayList<?>();

这是因为在构建时,Java必须知道您将选择哪种类型。


但在许多情况下,它被用作有界通配符。以典型的例子:

public void drawAll(List<? extends Shape> shapes) {
    //...
}

此方法有一个Shape列表。现在,如果您将其写为List<Shape>,则需要您提供ArrayList<Shape>LinkedList<Shape>或其他集合。但也许你的专门你的集合只包含Quadrilateral个实例(RectangleSquareTrapezium)。如果您在函数ArrayList<Quadrilateral>上使用drawAll(List<Shape> shapes),则会出现类型错误:实际上,List<Quadrilateral>不是List<Shape>,但是使用bounderies,您强制执行通用类型extends,例如来自另一种类型。

答案 1 :(得分:2)

使用通配符实例化泛型类型会生成编译错误,因为通配符表示任何类型,而实例化的ArrayList应具有具体类型。通配符可用于变量或参数类型,但不能在创建泛型类型的实例时使用。

this tutorial page中也提到了这一点:

  

在通用代码中,称为通配符的问号(?)表示未知类型。通配符可用于各种情况:作为参数,字段或局部变量的类型;有时作为返回类型(虽然更好的编程实践更具体)。 通配符永远不会用作泛型方法调用,泛型类实例创建或超类型的类型参数。

另一方面,在factory方法中,T是一个类型参数,将由编译器推断,并且由于List<?>表示任何类型,因此它被接受编译器。

答案 2 :(得分:0)

  

我们无法创建List l = new ArrayList();

如果你真的想这样做,你可以做到

List<?> l = new ArrayList<Object>();

List<?> l = new ArrayList<String>();

List<?> l = new ArrayList<Math>();

List<?> l = new ArrayList<SomeBogusIrrelevantClass>();

都是正确的。只需挑选任何满足界限的类型;它甚至不必与你正在做的事情有关。

从这里,您可以看到为什么您尝试做的事情是荒谬的 - 您有一个可能是ArrayList<Math>或可能是ArrayList<SomeBogusIrrelevantClass>的列表(您不会这样做)知道)。那么你能用它做什么呢?不多。

您无法向其中添加任何内容(null除外)。所以你有一个列表,其中元素只能有值null;唯一可以改变的是null个。但在这种情况下,您也可以使用整数。