在Java中创建Generic类实例的正确方法是什么?

时间:2009-03-25 15:23:55

标签: java generics

在Java中初始化Generic类的实例时,在语句的两边指定Type是否有任何好处?

或者换句话说,这两个有效陈述之间的区别是什么:

ArrayList<String> test = new ArrayList<String>();

ArrayList<String> test = new ArrayList();

(似乎第二个陈述不等同于:

ArrayList<String> test = new ArrayList<Object>();

作为无效的第三个语句并导致incompatible types编译错误。)

2 个答案:

答案 0 :(得分:14)

第二个语句与第一个语句或多或少等同,但仅仅因为泛型在运行时被删除。你会得到一个“未经检查的转换”警告,这就是我不喜欢的原因。

更好的方法是使用这样的静态泛型方法:

public static <T> List<T> newList() {
    return new ArrayList<T>();
}

然后再做

List<String> test = newList();

Google Collections就是这样做的。

(并且您应该几乎总是将您的列表声明为List,而不是ArrayList。稍后可以轻松切换实施。)

编辑:运动员在评论中询问两个声明之间的确切区别,以及为什么我说它们“或多或少相当”。由于type erasure,它们之间的唯一区别是警告。这是一小段代码比较它们:

import java.util.*;

class GenericDeclarationTest {
    public static void main(String[] args) {
        List<String> list1 = new ArrayList<String>();
        list1.add("");
        String s1 = list1.get(0);
        List<String> list2 = new ArrayList();
        list2.add("");
        String s2 = list2.get(0);
    }
}

这是生成的字节码(由javap -c GenericDeclarationTest打印):

Compiled from "GenericDeclarationTest.java"
class GenericDeclarationTest extends java.lang.Object{
GenericDeclarationTest();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   return

public static void main(java.lang.String[]);
  Code:
   0:   new     #2; //class java/util/ArrayList
   3:   dup
   4:   invokespecial   #3; //Method java/util/ArrayList."<init>":()V
   7:   astore_1
   8:   aload_1
   9:   ldc     #4; //String
   11:  invokeinterface #5,  2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
   16:  pop
   17:  aload_1
   18:  iconst_0
   19:  invokeinterface #6,  2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
   24:  checkcast       #7; //class java/lang/String
   27:  astore_2
   28:  new     #2; //class java/util/ArrayList
   31:  dup
   32:  invokespecial   #3; //Method java/util/ArrayList."<init>":()V
   35:  astore_3
   36:  aload_3
   37:  ldc     #4; //String
   39:  invokeinterface #5,  2; //InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
   44:  pop
   45:  aload_3
   46:  iconst_0
   47:  invokeinterface #6,  2; //InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
   52:  checkcast       #7; //class java/lang/String
   55:  astore  4
   57:  return

}

正如你所看到的(如果你有耐心),两者是相同的。

顺便说一句,在Java 7中这可能会变得更容易。proposal中有Project Coin用于“改进的通用实例创建类型推断”。如果它进行最终剪切,则语法为:

List<String> test = new ArrayList<>();
// or
Map<String, Object> test2 = new HashMap<>();

不太难打字,不是吗?

答案 1 :(得分:3)

冗余很烦人。您可能希望查看具有创建List的工厂方法的Google Collections

List<Double> doubleList = Lists.newLinkedList();

另请注意Java Generics are not covariant