Выбрать главу

} /* Output.

Rat. 1. 0; Manx. 2. 1. Cymric. 3. 2; Mutt. 4. 3. Pug. 5. 4. Cymric. 6. 5. Pug. 7. 6. Manx. 8. 7. 7 6 5 4 3 2 1 0

[Rat. Manx. Cymric. Mutt. Pug. Cymric. Pug. Manx] [Rat. Manx. Cymric. Cymric. Rat. EgyptianMau. Hamster. EgyptianMau] *///•-

Метод Pets.randomPet() используется для замены всех объектов Pet в списке, начиная с позиции 3 и далее.

LinkedList

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

Класс LinkedList также содержит методы, позволяющие использовать его в качестве стека, очереди (Queue) или двусторонней очереди (дека).

Некоторые из этих методов являются псевдонимами или модификациями для получения имен, более знакомых в контексте некоторого использования. Например, методы getFirst() и element() идентичны — они возвращают начало (первый элемент) списка без его удаления и выдают исключение NoSuch- ElementException для пустого списка. Метод реек() представляет собой неболь­шую модификацию этих двух методов: он возвращает null для пустого списка.

Метод addFirst() вставляет элемент в начало списка. Метод offer() делает то же, что add() и addLast() — он добавляет элемент в конец списка. Метод removeLast() удаляет и возвращает последний элемент списка.

Следующий пример демонстрирует схожие и различающиеся аспекты этих методов:

// hoiding/LinkedListFeatures java import typeinfo pets *; import java util *;

import static net.mindview util Print.*;

public class LinkedListFeatures {

public static void main(String[] args) { LinkedList<Pet> pets =

new LinkedList<Pet>(Pets arrayList(5)); print(pets); // Идентично

print("pets.getFirst()• " + pets getFirstO).

print ("pets element О " + pets.elementO);

// Различие проявляется только для пустых списков:

print("pets peekO: " + pets.peekO);

// Идентично, удаление и возврат первого элемента.

print("pets removeO: " + pets.removeO);

print ("pets removeFirstO: " + pets.removeFirstO);

// Различие проявляется только для пустых списков:             продолжение

print ("pets pollO " + pets poll О). print(pets).

pets addFirst(new RatO).

print("After addFirstO " + pets).

pets offer(Pets randomPetO).

print("After offer() " + pets).

pets.add(Pets randomPetO).

print ("After addO " + pets).

pets addLast(new HamsterO).

print ("After addLastO " + pets).

print ("pets removeLastO " + pets removeLastO).

}

} /* Output

[Rat, Manx. Cymric. Mutt. Pug]

pets getFirstO. Rat

pets elementO- Rat

pets.peek О Rat

pets.removeО: Rat

pets removeFirstO: Manx

pets.poll О Cymric

[Mutt. Pug]

After addFirstO: [Rat. Mutt. Pug] After offerO: [Rat. Mutt. Pug. Cymric] After addO: [Rat. Mutt. Pug. Cymric. Pug] After addLastO* [Rat. Mutt. Pug. Cymric. Pug. Hamster] pets removeLastO. Hamster *///:-

Результат Pets.arrayList() передается конструктору LinkedList для заполнения. Присмотревшись к интерфейсу Queue, вы найдете в нем методы element(), offer(), peek(), poll() и remove(), добавленные в LinkedList для использования в реализации очереди (см. далее).

Стек

Стек часто называют контейнером, работающим по принципу «первым вошел, последним вышел» (LIFO). То есть элемент, последним занесенный в стек, бу­дет первым, полученным при извлечении из стека.

В классе LinkedList имеются методы, напрямую реализующие функциональ­ность стека, поэтому вы просто используете LinkedList, не создавая для стека но­вый класс. Впрочем, иногда отдельный класс для контейнера-стека лучше справ­ляется с задачей:

//. net/mi ndvi ew/uti1/Stack java // Создание стека из списка LinkedList. package net.mindview.uticlass="underline" import java.util.LinkedList:

public class Stack<T> {

private LinkedList<T> storage = new LinkedList<T>(); public void push(T v) { storage.addFirst(v); } public T peek О { return storage. getFirstO: } public T popO { return storage removeFirstO: } public boolean emptyО { return storage.isEmptyО: }

public String toStringO { return storage.toStringO. } } ///:-

Это простейший пример определения класса с использованием параметри­зации. Суффикс <Т> после имени класса сообщает компилятору, что тип явля­ется параметризованным по типу Т — при использовании класса на место Т бу­дет подставлен фактический тип. Фактически такое определение означает: «Мы определяем класс Stack для хранения объектов типа Т». Stack реализуется на базе LinkedList, также предназначенного для хранения типа Т. Обратите вни­мание: метод push() получает объект типа Т, а методы реек() и рор() возвращают объект типа Т. Метод реек() возвращает верхний элемент без извлечения из сте­ка, а метод рор() удаляет и возвращает верхний элемент. Простой пример использования нового класса Stack:

//• hoiding/StackTest.java import net.mindview util.*:

public class StackTest {

public static void main(String[] args) {

Stack<String> stack = new Stack<String>(): for(String s • "My dog has fleas" .splitC' "))

stack.push(s); whi led stack. emptyO)

System out pri nt(stack.pop() + " ");

}

} /* Output: fleas has dog My *///:-

Если вы хотите использовать класс Stack в своем коде, вам придется либо полностью указать пакет, либо изменить имя класса при создании объекта; в противном случае, скорее всего, возникнет конфликт с классом Stack из паке­та java.util. Пример использования имен пакетов при импортировании java. util.* в предыдущем примере:

//: holding/StackCollision.java import net.mindview.util.*:

public class StackCol1ision {

public static void main(String[] args) {

net.mindview.util.Stack<String> stack =

new net.mindview.util.Stack<String>(); for(String s : "My dog has fleas".splitC "))

stack.push(s): whi led stack, empty О)

System, out. pri nt (stack. popO + " "); System, out. printlnO; java.util.Stack<String> stack2 =

new java.util.Stack<String>(): for(String s : "My dog has fleas".splitC' "))

stack2.push(s); while( !stack2 emptyO)

System.out print(stack2.pop() + " ").

}

fleas has dog My fleas has dog My *///:-

В java.util нет общего интерфейса Stack — вероятно, из-за того, что имя было задействовано в исходной, неудачно спроектированной версии java. util.Stack для Java 1.0. Хотя класс java.util.Stack существует, LinkedList обеспечивает более качественную реализацию стека, и решение net.mindview.util. Stack является предпочтительным.

Множество

В множествах (Set) каждое значение может храниться только в одном экземп­ляре. Попытки добавить новый экземпляр эквивалентного объекта блокируются. Множества часто используются для проверки принадлежности, чтобы вы мог­ли легко проверить, принадлежит ли объект заданному множеству. Следова­тельно, важнейшей операцией Set является операция поиска, поэтому на прак­тике обычно выбирается реализация HashSet, оптимизированная для быстрого поиска.

Set имеет такой же интерфейс, что и Collection. В сущности, Set и является Collection, но обладает несколько иным поведением (кстати, идеальный пример использования наследования и полиморфизма: выражение разных концепций поведения). Пример использования HashSet с объектами Integer:

//• hoiding/SetOfInteger.java import java.util.*,

public class SetOfInteger {

public static void main(String[] args) { Random rand = new Random(47); Set<Integer> intset = new HashSet<Integer>(): for(int i = 0: i < 10000; i++)

i ntset.add(rand.nextInt(30)): System.out.printin(intset):