Почему я могу использовать метод Arrays.asList с объектом, объявленным для интерфейса, List, но не тогда, когда он объявлен как экземпляр класса ArrayList?

#java #arrays #list #arraylist #collections

#java #массивы #Список #arraylist #Коллекции

Вопрос:

 //Splitting a string and passing it to a String Array
String[] b1 = a1.split("");

//The Following throws a compile-time error
ArrayList<String> arrayList1 =  new ArrayList<String>();
arrayList1 = Arrays.asList(b1);

//The following works
List<String> arrayList1 =  new ArrayList<String>();
arrayList1 = Arrays.asList(b1);
  

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

Комментарии:

1. Все немецкие овчарки — собаки, но не каждая собака является немецкой овчаркой. Здесь: ArrayList «is-a» List . Таким образом, вы можете назначить ArrayList для List . Но List также может быть другого типа (runtime), поэтому вы не можете назначить List более конкретный ArrayList .

2. Обратите внимание, что список, возвращаемый Arrays.asList не java.util.ArrayList . Это совершенно другой класс, который также назван ArrayList , помещенный внутри java.util.Arrays.ArrayList

3. Вы должны понимать ссылки . Ваши переменные имеют тип ссылки , и назначение новой ссылки перезаписывает старую. Перезапись ссылки не имеет ничего общего с объектом. Другими словами, инициализация arrayList1 = new ArrayList<String>() совершенно бессмысленна, когда вы перезаписываете ссылку прямо в следующем операторе другой ссылкой. Присвоение допустимо, когда тип переменной совместим со ссылкой. Старая ссылка и объект, на который она указывает, совершенно не имеют значения.

Ответ №1:

ArrayList реализует List интерфейс, поэтому он должен хорошо работать.

Нет, это не так, как это работает. Если что-то возвращает реализацию интерфейса, вы можете назначить его объекту, объявленному как этот интерфейс, а не наоборот.

Это то, что вы делаете, когда вы делаете

 List<String> arrayList1 =  new ArrayList<String>();
  

Что абсолютно законно.

Но что, если asList возвращает что-то, что является списком, но не ArrayList (что здесь и происходит)? Вы получаете сообщение об ошибке, потому что вы присваиваете что-то, что не является ArrayList (и не происходит от него) ArrayList .

Также обратите внимание, что, как только вы это сделаете arrayList1 = Arrays.asList(b1); во втором тесте, тот факт, что вы назначили new ArrayList для arrayList1 , совершенно не имеет значения, поскольку вы перезаписываете его в следующей строке, так что arrayList1 это просто a List , как объявлено.

Ответ №2:

Java статически типизирована, когда вы говорите, что переменная является a, String тогда вы не можете назначить int ей . То же самое относится и к вашему примеру. Когда вы объявляете arrayList1 как a ArrayList<String> , вы не можете назначить List<String> ему . Потому что вы не можете быть уверены, что значение, возвращаемое из Arrays.asList() , действительно является экземпляром java.util.ArrayList .

Также будьте осторожны, существует два класса Java с именем ArrayList . Тот, от java.util и тот, от java.util.Arrays . Первый является public , а второй находится private внутри Arrays класса

Ответ №3:

Arrays.asList(b1) возвращает объект типа java.util.Массивы.ArrayList, который является вложенным классом в массивах.

Другими словами, ваш вопрос заключается в том, почему b1 типа java.util.Массивы.ArrayList не может быть приведен к arrayList1, который имеет тип java.util.ArrayList : это два совершенно разных типа, которые вообще не связаны.

Если вам нужен java.util.Вы можете просто создать копию:

ArrayList arrayList1 = новый ArrayList<>(Arrays.asList(b1));

С уважением