java - 在 Java 中创建泛型类实例的正确方法是什么?

标签 java generics

在 Java 中初始化泛型类的实例时,在语句的两边指定类型有什么好处吗?

或者换句话说,这两个有效语句之间有什么区别:

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

和:

ArrayList<String> test = new ArrayList();

(似乎第二条语句不等同于:

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

作为无效的第三条语句并导致不兼容的类型编译错误。)

最佳答案

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

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

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

然后做

List<String> test = newList();

这就是 Google Collections 所做的。

(而且您几乎应该始终将列表声明为 List,而不是 ArrayList。这样可以在以后轻松切换实现。)

编辑: dribeas 在评论中询问了这两个声明之间的确切区别是什么,以及为什么我说它们“或多或少等价”。因为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 中可能会变得更容易。有一个 proposalProject Coin对于“改进的通用实例创建的类型推断”。如果它进行最终剪辑,语法将是:

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

打字不难吧?

关于java - 在 Java 中创建泛型类实例的正确方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/682092/

相关文章:

java - 这是地道的Java吗?

java - 错误架构更新 :237 - near "from": syntax error

java - Java泛型方法中的类型参数

ios - Swift 泛型类、继承和协方差

java - 构造函数和字符串第 2 部分字母示例

java - 转换后的 PFX SSL 证书抛出 SSLHandshakeException?

java - 与 Java Applet 交互

java - 泛型: token 语法错误 "extends", , 预期

java - 在java中创建静态泛型工厂?

java - 如果我已经有泛型实现,如何声明接口(interface)方法