Почему класс arraylist реализует List, а также расширяет AbstractList?

Реализация java.util.ArrayList реализует List а также расширяет AbstractList. Но в java-документах вы можете видеть, что AbstractList уже реализует List. Тогда не было бы лишним реализовать List, а также расширить AbstractList?
Мой второй вопрос

Пожалуйста, ознакомьтесь со следующим кодом:

String str = "1,2,3,4,5,6,7,8,9,10";
String[] stra = str.split(",");
List<String> a = Arrays.asList(stra);

Метод Arrays.asList() класса Arrays содержит собственную реализацию ArrayList. Но это только расширяет AbstractList, но не реализует List. Но приведенный выше код компилируется.
НО, когда код изменен на следующий

String str = "1,2,3,4,5,6,7,8,9,10";
String[] stra = str.split(",");
java.util.ArrayList<String> a = Arrays.asList(stra);

Я получаю сообщение об ошибке: cannot convert form List<String> to ArrayList<String>
В чем причина этого?
РЕДАКТИРОВАТЬ
Arrays.asList() возвращает свою собственную реализацию ArrayList. Проверьте это.

Ответ 1

Для вашего первого вопроса посмотрите, почему ArrayList имеет "реализует список"?


Чтобы ответить на второй вопрос

java.util.ArrayList<String> a = Arrays.asList(stra);

как вы упомянули, Arrays.asList возвращает свою собственную реализацию AbstractList, и, к сожалению, создатели этого кода также назвали этот класс ArrayList. Теперь, поскольку мы не можем нарисовать горизонтально, но только вертикально возвращенный список массивов нельзя отнести к java.utli.ArrayList а только к java.util.AbstractList или к его супер-типам, например java.util.List, поэтому ваш первый пример кода работает.

Ответ 2

Тогда не было бы лишним реализовать List, а также расширить AbstractList?

Да, это на 100% избыточно. Однако разработчики Java добавили интерфейсы очень последовательно во всю публичную реализацию библиотеки коллекций:

  • LinkedList<E> и ArrayList<E> расширяют AbstractList<E> который реализует List<E>, а затем сам реализует List<E>.
  • HashSet<E> и TreeSet<E> расширяют AbstractSet<E> который реализует Set<E>, а затем реализует Set<E>.
  • HashMap<K,V> и TreeMap<E> расширяют AbstractMap<K,V> который реализует Map<K,V>, а затем реализует Map<K,V>.

Я понимаю, что они сделали это для целей документации: авторы хотели показать, что ArrayList<E> - это прежде всего List<E>; тот факт, что ArrayList<E> расширяет AbstractList<E> является менее значительной деталью его реализации. То же самое касается других типов коллекций.

Обратите внимание, что Arrays.ArrayList<E> не является общедоступным, поэтому его авторы не Arrays.ArrayList<E> List<T>.

Что касается неудачного преобразования, это не должно удивлять, потому что внутренний класс Arrays.ArrayList<E> и открытый класс ArrayList<E> не связаны друг с другом.

Ответ 3

Arrays.asList возвращает список. Поэтому отбрасывание его в ArrayList небезопасно, так как вы не знаете, какой тип списка возвращается (зависит от типа массива, из которого создается список). Ваш второй фрагмент хочет, чтобы ArrayList неявно. Следовательно, он терпит неудачу, пока ваш первый фрагмент компилируется отлично, потому что он ожидает Список. Вы можете do-

ArrayList<String> a = new ArrayList<String>(Arrays.asList(stra));

Ответ 4

1) ArrayList implements List is redundant, но все еще легально. Дизайнеры JCF (Java Collection Framework) могли бы ответить на вопрос. Поскольку ведущий JCF-дизайнер J.Bloch не говорит, почему это так в "Эффективной Java", похоже, мы никогда не узнаем, почему.

2) Возвращает Arrays.asList

public class Arrays {
   ...

    private static class ArrayList<E> extends AbstractList<E>
        implements RandomAccess, java.io.Serializable
    {
...

это не java.util.ArrayList, и его нельзя отбросить

Ответ 5

Ответ на ваш первый вопрос заключается в том, что реализация List - это контракт. Этот контракт может быть определен как AbstractList, так и ArrayList. ArrayList реализует List для публикации факта, который будет уважать контракт List в будущем, когда может потребоваться продлить не из AbstractList, который может или не может реализовать List.

Для второго вопроса: Arrays.asList возвращает список. Может случиться так, что в текущей реализации возвращается ArrayList. В следующей версии может быть возвращен другой список LinkedList, например, и контракт (определенный подписи метода) будет по-прежнему соблюдаться.

Ответ 6

Полагаю, есть причина. Это только моя мысль, и я не нашел ее нигде в JLS.

Если я разработчик, который пишет API, который будет широко использоваться, зачем мне это делать?

Для этого нет абсолютно никаких оснований, но рассмотрите этот сценарий, где я написал интерфейс List и предоставил реализацию ArrayList для интерфейса List.

До сих пор я еще не писал абстрактного класса AbstractList.

Однажды возникает требование, когда меня просят написать еще несколько реализаций интерфейса List где большинство из них имеют похожие или одинаковые конкретные методы abstract методов в интерфейсе List.

Я продолжу и напишу AbstractList с необходимой реализацией для всех этих методов. Но теперь мне не понравится эта половина моих классов для реализации интерфейса List а половина из них расширяет AbstractList.

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

Примечание. Это единственное мое мнение.

Ответ 7

Я буду прост и прям в своих ответах.

не будет ли избыточным реализовать List, а также расширить AbstractList?

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

Метод Arrays.asList() класса Arrays содержит собственную реализацию ArrayList. Но это только расширяет AbstractList, но не реализует List.

Как вы могли видеть, это было избыточно, вам не нужно повторно объявлять реализацию интерфейса List, если AbstractList уже объявляет эту реализацию.

Я получаю сообщение об ошибке: невозможно преобразовать форму List в ArrayList. В чем причина этого?

Arrays.asList() возвращает список, это может быть любой тип списка. ArrayList, реализованный в этом коде, не является тем же самым ArrayList из java.util.ArrayList, они просто используют одно и то же имя, но это не тот же код.

Ответ 8

просто хочу дополнить ответы на вопрос 2

java.util.ArrayList<String> a=Arrays.asList(stra);

компилятор просто знает, что тип возврата Arrays.asList - List, но не знает его точной реализации, которая может быть не java.util.ArrayList. Таким образом, вы получили эту ошибку времени компиляции.

Несоответствие типов: невозможно преобразовать из списка в ArrayList

вы можете принудительно заставить верхний текст явно так,

java.util.ArrayList<String> a =(java.util.ArrayList<String>)Arrays.asList(stra);

Код будет скомпилирован успешно, но произойдет исключение во время выполнения,

java.lang.ClassCastException: java.util.Arrays $ ArrayList нельзя отбрасывать в java.util.ArrayList

это потому, что java.util.Arrays$ArrayList (тип реализации, который возвращает Arrays.asList) не является подтипом java.util.ArrayList.