Guava图书馆的Lists.newArraylist()如何运作?

时间:2014-05-12 17:41:12

标签: java generics guava

我试图了解Lists.newArrayList()如何知道要返回的列表类型。 我看到了函数newArrayList()的{​​{3}},但它只返回了通用类型E的ArrayList

public static <E> ArrayList<E> newArrayList() {
  return new ArrayList<E>();
}

但是,当我调用该函数时,我没有传递任何此类信息。

List<String> testList = Lists.newArrayList();

它如何知道我想要的ArrayList类型?

我读过有关泛型和TypeToken的内容,但无法通过代码与之相关。

4 个答案:

答案 0 :(得分:14)

因为编译器可以从变量声明中推断出类型。

示例:

List<String> list = Lists.newArrayList(),

编译器将理解集合的类型(E的类型)将为<String>,因为您希望获得字符串列表。

避免重写整个&lt;&gt;是有用的。参数,但使用Java7和菱形运算符,您可以使用

来避免它
List<String> list = new ArrayList<>();

(想象一下,List<List<String>>你应该重写List<List<String>>

我为你找到了这个:

  

Java编译器利用目标类型来推断a的类型参数      泛型方法调用。表达式的目标类型是Java编译器所期望的数据类型,具体取决于表达式的显示位置。考虑方法Collections.emptyList,声明如下:

static <T> List<T> emptyList();
  

考虑以下赋值语句:

List<String> listOne = Collections.emptyList();
  

此语句期待List的实例;此数据类型是目标类型。因为方法emptyList返回List类型的值,所以编译器推断类型参数T必须是值String。这适用于Java SE 7和8.或者,您可以使用类型见证并指定T的值,如下所示:

List<String> listOne = Collections.<String>emptyList();
  

但是,在这种情况下,这不是必需的。不过,在其他情况下这是必要的。请考虑以下方法:

void processStringList(List<String> stringList) {
    // process stringList
}
  

假设您要使用空列表调用方法processStringList。在Java SE 7中,以下语句不编译:

processStringList(Collections.emptyList());
  

Java SE 7编译器生成类似于以下内容的错误消息:

List<Object> cannot be converted to List<String>
  

编译器需要类型参数T的值,因此它以值Object开头。因此,Collections.emptyList的调用返回List类型的值,该值与方法processStringList不兼容。因此,在Java SE 7中,您必须指定type参数值的值,如下所示:

processStringList(Collections.<String>emptyList());
  

Java SE 8中不再需要这个。目标类型的概念已经扩展为包含方法参数,例如方法processStringList的参数。在这种情况下,processStringList需要一个List类型的参数。方法Collections.emptyList返回List的值,因此使用List的目标类型,编译器推断类型参数T的值为String。因此,在Java SE 8中,以下语句编译:

processStringList(Collections.emptyList());
  

有关详细信息,请参阅Lambda表达式中的目标类型。

阅读this

答案 1 :(得分:4)

它可以通过类型推断来实现。

简单来说,您可以进行如下任务:

List<String> list = newArrayList();

其中newArrayList()可能是:

static <E> List<E> newArrayList() {
    return new ArrayList<>();
}

这里编译器需要确定E类型变量的类型。为此,它将使用作业的左侧,其中包含List<String>,因此E == String。现在它知道了类型变量,一切都没问题。

与使用番石榴进行如此简单的任务相反,我建议你简单地写一下:

List<String> list = new ArrayList<>();

我会称之为更清洁,不需要(不必要的)外部依赖。

答案 2 :(得分:2)

简短回答是Type Inference

这是发生了什么。你不是简单地打电话给Lists.newArrayList();你也将它分配给一个变量,比如

List<Person> people = Lists.newArrayList();

由于您已在变量声明中指定了类型参数,因此Java能够“推断”(计算出)您在新ArrayList中需要的类型参数,因此您无需指定它们。 / p>

答案 3 :(得分:0)

编译器从变量/方法声明中推断出类型。 见http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html