• Карта: набор пар объектов «ключ-значение», с возможностью выборки по ключу. ArrayList позволяет искать объекты по порядковым номерам, поэтому в каком-то смысле он связывает числа с объектами. Класс Map (карта — также встречаются термины ассоциативный массив и словарь) позволяет искать объекты по другим объектам — например, получить объект значения по объекту ключа, по аналогии с поиском определения по слову.
Хотя на практике это не всегда возможно, в идеале весь программный код должен писаться в расчете на взаимодействие с этими интерфейсами, а точный тип указывается только в точке создания. Следовательно, объект List может быть создан так:
List<Apple> apples = new ArrayList<Apple>():
Обратите внимание на восходящее преобразование ArrayList к List, в отличие от предыдущих примеров. Если позднее вы решите изменить реализацию, достаточно сделать это в точке создания:
List<Apple> apples = new LinkedList<Apple>();
Итак, в типичной ситуации вы создаете объект реального класса, повышаете его до соответствующего интерфейса, а затем используете интерфейс во всем остальном коде.
Такой подход работает не всегда, потому что некоторые классы обладают дополнительной функциональностью. Например, LinkedList содержит дополнительные методы, не входящие в интерфейс List, а ТгееМар — методы, не входящие в Map. Если такие методы используются в программе, восходящее преобразование к обобщенному интерфейсу невозможно.
Интерфейс Collection представляет концепцию последовательности как способа хранения группы объектов. В следующем простом примере интерфейс Collection (представленный контейнером ArrayList) заполняется объектами Integer, с последующим выводом всех элементов полученного контейнера:
//: hoiding/SimpleCol1ection.java
import java.util .*;
public class SimpleCollection {
public static void main(String[] args) {
Collection<Integer> с = new ArrayList<Integer>(); for(int i = 0; i < 10; i++)
c.add(i); // Автоматическая упаковка for(Integer i : c)
System.out.print(i + ". ");
}
} /* Output:
0. 1. 2. 3. 4, 5. 6. 7, 8-. 9.
*///•-
Поскольку в этом примере используются только методы Collection, подойдет объект любого класса, производного от Collection, но ArrayList является самым простейшим типом последовательности.
' Все коллекции поддерживают перебор в синтаксисе foreach, как в приведенном примере. Позднее в этой главе будет рассмотрена другая, более гибкая концепция итераторов.
Семейства Arrays и Collections в java.util содержат вспомогательные методы для включения групп элементов в коллекции. Метод Arrays.asList() получает либо массив, либо список элементов, разделенных запятыми, и преобразует его в объект List. Метод Collections.addAUQ получает объект Collection и либо массив, либо список, разделенный запятыми, и добавляет элементы в Collection. Пример:
//• hoiding/AddingGroups java
// Добавление групп элементов в объекты Collection
import java.util *;
public class AddingGroups {
public static void main(String[] args) { Collection<Integer> collection =
new ArrayList<Integer>(Arrays.asList(l, 2, 3, 4, 5)); Integer[] morelnts = { 6. 7. 8. 9. 10 }; collection.addAll(Arrays.asList(morelnts)); // Работает намного быстрее, но таким способом // невозможно сконструировать Collection: Collections.addAll(collection, 11, 12, 13, 14, 15); Col lections.addAll(collection, morelnts); // Создает список на основе массива: List<Integer> list = Arrays.asList(16. 17, 18, 19, 20); list set(l, 99); // Можно - изменение элемента // list.add(21); // Ошибка времени выполнения - нижележащий // массив не должен изменяться в размерах
}
} ///:-
Конструктор Collection может получать другой объект Collection, используемый для его инициализации, поэтому для передачи исходных данных можно воспользоваться методом Arrays.asList(). Однако метод Collections.addAll() работает намного быстрее, и вы с таким же успехом можете сконструировать Collection без элементов, а затем вызвать Collections.addAll — этот способ считается предпочтительным.
Методу Collection.addAll() в аргументе может передаваться только другой объект Collection, поэтому он уступает в гибкости методам Arrays.asList() и Collections.addAll(), использующим переменные списки аргументов.
Также можно использовать вывод Arrays.asList() напрямую, в виде List, но в этом случае нижележащим представлением будет массив, не допускающий изменения размеров. Вызов add() или delete() для такого списка приведет к попытке изменения размера массива, а это приведет к ошибке во время выполнения.
Недостаток Arrays.asList() заключается в том, что он пытается «вычислить» итоговый тип List, не обращая внимания на то, что ему присваивается. Иногда это создает проблемы:
//: hoiding/AsListInference.java // Arrays.asListO makes its best guess about type, import java.util.*;
class Snow {}
class Powder extends Snow {} class Light extends Powder {} class Heavy extends Powder {} class Crusty extends Snow {} class Slush extends Snow {}
public class AsListInference {
public static void main(String[] args) { List<Snow> snowl = Arrays.asList(
new CrustyO. new SlushO. new PowderO);
// He компилируется- // List<Snow> snow2 = Arrays.asList( // new LightO. new HeavyO); // Сообщение компилятора: //found java.util.List<Powder> // required, java util List<Snow>
II Collections.addAllО работает нормально:
List<Snow> snow3 = new ArrayList<Snow>():
Col 1 ecti ons. addAl 1 (snow3, new LightO. new HeavyO);
II Передача информации посредством уточнения // типа аргумента
List<Snow> snow4 = Arrays <Snow>asList( new LightO, new HeavyO),
}
} ///:-
При попытке создания snow2, Arrays.asList() создает List<Powder> вместо List <Snow>, тогда как Collections.addAll() работает нормально, потому что целевой тип определяется первым аргументом. Как видно из создания snow4, в вызов Arrays.asList() можно вставить «подсказку», которая сообщает компилятору фактический тип объекта List, производимого Arrays.asList().
С контейнерами Map дело обстоит сложнее, и стандартная библиотека Java не предоставляет средств их автоматической инициализации, кроме как по содержимому другого объекта Map.
Для получения печатного представления массива необходимо использовать метод Arrays.toString, но контейнеры отлично выводятся и без посторонней помощи. Следующий пример демонстрирует использование основных типов контейнеров:
II: elclass="underline" Printi ngContai ners.java II Вывод контейнеров по умолчанию import java.util.*;
import static net.mindview.util.Print.*;
public class PrintingContainers {
static Collection fill(Collection<String> collection) { collection. addC'rat"): collection.addC'cat"); collection.adde'dog"): col lection.add("dog"); return collection;
}
static Map fill(Map<String,String> map) {
map. put ("rat", "Fuzzy"); продолжение &
map.put("cat". "Rags"), тар.put("dog". "Bosco"); map.put("dog", "Spot"); return map;
}
public static void main(String[] args) {
pri nt(fi11(new ArrayLi st<Stri ng>())); print(fill(new LinkedList<String>())); pri nt(fi11(new HashSet<Stri ng>())); pri nt(fi11(new TreeSet<Stri ng>())); pri nt(fi11(new Li nkedHashSet<Stri ng>())); pri nt(fi11(new HashMap<Stri ng.Stri ng>())); print(fill(new TreeMap<String,String>())); print(fi11(new LinkedHashMap<String,String>()));
}
} /* Output: [rat, cat, dog, dog] [rat, cat. dog, dog] [dog, cat, rat] [cat, dog, rat] [rat. cat. dog]