Мне интересно, кто-нибудь использует (2)?
Да. Но редко по веской причине (ИМО).
И люди получают ожоги, потому что они использовали ArrayList
, когда они должны были использовать List
:
Служебные методы, такие как Collections.singletonList(...)
или Arrays.asList(...)
, не возвращают ArrayList
.
Методы в List
API не гарантируют возвращение списка того же типа.
Например, кто-то обгорел, в https://stackoverflow.com/a/1481123/139985 у плаката были проблемы с "нарезкой", потому что ArrayList.sublist(...)
не возвращает ArrayList
... и он разработал свой код для использования ArrayList
как тип всех его переменных списка. В итоге он «решил» проблему, скопировав подсписок в новый ArrayList
.
Аргумент о том, что вам нужно знать, как ведет себя List
, в значительной степени рассматривается с помощью интерфейса маркера RandomAccess
. Да, это немного неуклюже, но альтернатива хуже.
Кроме того, как часто ситуация на самом деле требует использования (1) над (2) (т. Е. Где (2) будет недостаточно… кроме «кодирования для интерфейсов» и лучших практик и т. Д.)
Часть вопроса «как часто» объективно не может быть решена.
(и могу ли я получить пример)
Иногда приложение может требовать использования методов в ArrayList
API, которые не в List
API. Например, ensureCapacity(int)
, trimToSize()
или removeRange(int, int)
. (И последний из них возникнет, только если вы создали подтип ArrayList, который объявляет метод public
.)
Это единственная разумная причина для кодирования класса, а не интерфейса, IMO.
(Теоретически возможно, что вы получите небольшое улучшение производительности ... при определенных обстоятельствах ... на некоторых платформах ... но если вам действительно не нужны эти последние 0,05%, делать это не стоит. это не веская причина, ИМО.)
Вы не можете написать эффективный код, если не знаете, эффективен ли произвольный доступ или нет.
Это верный момент. Тем не менее, Java предоставляет лучшие способы справиться с этим; например, * * тысяча шестьдесят-шести
public <T extends List & RandomAccess> void test(T list) {
// do stuff
}
Если вы вызовете это со списком, который не реализует RandomAccess
, вы получите ошибку компиляции.
Вы также можете динамически тестировать ... используя instanceof
... если статическая типизация слишком неудобна. И вы могли бы даже написать свой код для использования различных алгоритмов (динамически) в зависимости от того, поддерживает ли список произвольный доступ.
Обратите внимание, что ArrayList
- не единственный класс списка, который реализует RandomAccess
. Другие включают CopyOnWriteList
, Stack
и Vector
.
Я видел, как люди приводят один и тот же аргумент в отношении Serializable
(потому что List
не реализует его) ... но описанный выше подход также решает эту проблему. (В той степени, в которой это разрешимо на всех с использованием типов времени выполнения. ArrayList
не сможет сериализоваться, если какой-либо элемент не сериализуем.)