Тип списка против типа ArrayList в Java - PullRequest
517 голосов
/ 17 февраля 2010
(1) List<?> myList = new ArrayList<?>();

(2) ArrayList<?> myList = new ArrayList<?>();

Я понимаю, что с помощью (1) реализации интерфейса List можно поменять местами. Кажется, что (1) обычно используется в приложении независимо от необходимости (я сам всегда использую это).

Мне интересно, кто-нибудь использует (2)?

Кроме того, как часто (и я могу привести пример) ситуация фактически требует использования (1) over (2) (то есть, где (2) будет недостаточно ... кроме кодирования интерфейсы и лучшие практики и т. д.)

Ответы [ 15 ]

3 голосов
/ 23 декабря 2016

Кто-то спросил это снова (дубликат), что заставило меня немного углубиться в этом вопросе.

public static void main(String[] args) {
    List<String> list = new ArrayList<String>();
    list.add("a");
    list.add("b");

    ArrayList<String> aList = new ArrayList<String>();
    aList.add("a");
    aList.add("b");

}

Если мы используем средство просмотра байт-кода (я использовал http://asm.ow2.org/eclipse/index.html), мы увидим следующее (только инициализация и назначение списка) для нашего списка сниппета:

   L0
    LINENUMBER 9 L0
    NEW ArrayList
    DUP
    INVOKESPECIAL ArrayList.<init> () : void
    ASTORE 1
   L1
    LINENUMBER 10 L1
    ALOAD 1: list
    LDC "a"
    INVOKEINTERFACE List.add (Object) : boolean
    POP
   L2
    LINENUMBER 11 L2
    ALOAD 1: list
    LDC "b"
    INVOKEINTERFACE List.add (Object) : boolean
    POP

и для alist :

   L3
    LINENUMBER 13 L3
    NEW java/util/ArrayList
    DUP
    INVOKESPECIAL java/util/ArrayList.<init> ()V
    ASTORE 2
   L4
    LINENUMBER 14 L4
    ALOAD 2
    LDC "a"
    INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
    POP
   L5
    LINENUMBER 15 L5
    ALOAD 2
    LDC "b"
    INVOKEVIRTUAL java/util/ArrayList.add (Ljava/lang/Object;)Z
    POP

Разница в список в итоге вызывает INVOKEINTERFACE , тогда как aList вызывает INVOKEVIRTUAL . В соответствии со ссылкой на плагин Bycode Outline,

invokeinterface используется для вызова метода, объявленного в Java интерфейс

в то время как invokevirtual

вызывает все методы, кроме методов интерфейса (которые используют invokeinterface), статические методы (которые используют invokestatic) и несколько особые случаи обрабатываются invokespecial.

В итоге invokevirtual выскакивает objectref из стека, в то время как для invokeinterface

интерпретатор выталкивает 'n' элементов из стека операндов, где 'n' - 8-битный без знака целочисленный параметр, взятый из байт-кода. Первый из этих предметов objectref, ссылка на объект, метод которого вызывается.

Если я правильно понимаю, разница в том, как каждый способ извлекает objectref .

3 голосов
/ 27 октября 2015

Список - это интерфейс. У него нет методов. Когда вы вызываете метод для ссылки на список. Фактически он вызывает метод ArrayList в обоих случаях.

А в будущем вы можете изменить List obj = new ArrayList<> на List obj = new LinkList<> или другой тип, который реализует Список интерфейса.

2 голосов
/ 17 февраля 2010

Единственный случай, когда мне известно, где (2) может быть лучше, - это использование GWT, потому что это уменьшает площадь приложения (не моя идея, но команда веб-инструментария Google так говорит). Но для обычного Java-запуска внутри JVM (1), вероятно, всегда лучше.

1 голос
/ 16 июня 2018
Интерфейс

List имеет несколько различных классов - ArrayList и LinkedList.LinkedList используется для создания индексированных коллекций и ArrayList - для создания отсортированных списков.Таким образом, вы можете использовать любой из них в своих аргументах, но вы можете позволить другим разработчикам, которые используют ваш код, библиотеку и т. Д., Использовать разные типы списков, не только те, которые вы используете, поэтому в этом методе

ArrayList<Object> myMethod (ArrayList<Object> input) {
   // body
}

вы можете использовать его только с ArrayList, но не LinkedList, но вы можете разрешить использовать любой из List классов в других местах, где используется этот метод, это просто ваш выбор, поэтому использование интерфейса можетразрешить это:

List<Object> myMethod (List<Object> input) {
   // body
}

В аргументах этого метода вы можете использовать любой из List классов, которые вы хотите использовать:

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

list.add ("string");

myMethod (list);

ВЫВОД:

Используйте интерфейсы везде, где это возможно, не ограничивайте себя или других в использовании различных методов, которые они хотят использовать.

1 голос
/ 17 февраля 2010

Я бы сказал, что 1 предпочтительнее, если

  • вы зависите от реализации необязательного поведения * в ArrayList, в этом случае явное использование ArrayList более понятно
  • Вы будете использовать ArrayList в вызове метода, который требует ArrayList, возможно, для необязательного поведения или характеристик производительности

Я предполагаю, что в 99% случаев вы можете обойтись с List, который является предпочтительным.

  • например removeAll или add(null)
...