Как правильно создать экземпляр класса Generic в Java? - PullRequest
1 голос
/ 25 марта 2009

При инициализации экземпляра класса Generic в Java есть ли какая-либо польза от указания типа с обеих сторон оператора?

Или, другими словами, в чем разница между этими двумя действительными утверждениями:

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

и

ArrayList<String> test = new ArrayList();

(Кажется, второе утверждение не эквивалентно:

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

в качестве третьего оператора недействителен и вызывает incompatible types ошибку компиляции.)

Ответы [ 2 ]

14 голосов
/ 25 марта 2009

Второе утверждение оказывается более или менее эквивалентным первому, но только потому, что генерики стираются во время выполнения. Вы получите предупреждение «непроверенное преобразование», поэтому оно мне не нравится.

Лучший способ - использовать статический универсальный метод, подобный этому:

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

, а затем сделать

List<String> test = newList();

Это то, что делает Google Collections.

(И вы почти всегда должны объявлять свои списки как List, а не как ArrayList. Позволяет легко переключать реализацию позже.)

Редактировать: dribeas спросил в комментариях, какова точная разница между этими двумя объявлениями, и почему я сказал, что они "более или менее эквивалентны". Из-за стирания типа единственным отличием между ними является предупреждение. Вот небольшой фрагмент кода, сравнивающий их:

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. Существует предложение в Project Coin для «Улучшенного вывода типов для создания общего экземпляра». Если это сделает окончательный вариант, синтаксис будет:

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

Не слишком сложно набрать, не так ли?

3 голосов
/ 25 марта 2009

Эта избыточность раздражает. Возможно, вы захотите взглянуть на Коллекции Google , у которых есть фабричные методы, которые создают List с таким образом:

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

Также обратите внимание, что Обобщения Java не являются ковариантными .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...