Эккель Брюс
Шрифт:
}
public String toStringO {
return "(" + first + " + second + " +
third + " + fourth + \ " + fifth + ")";
}
} ///-
Чтобы воспользоваться этими классами, достаточно определить кортеж нужной длины как возвращаемое значение функции, а затем создать и вернуть его командой return:
II: generics/TupleTest.java i mport net.mi ndvi ew.uti1.*;
class Amphibian {} class Vehicle {}
public class TupleTest {
static TwoTuple<String.Integer> fO {
// Автоматическая упаковка преобразует int в Integer: return new TwoTuple<String.Integer>("hi", 47);
}
static ThreeTuple<Amphibian,String,Integer> g {
return new ThreeTuple<Amphibian, String, Integer>( new AmphibianO. "hi", 47);
}
static
FourTuple<Vehicle,Amphibian,String,Integer> hO { return
new FourTuple<Vehicle,Amphibian,String.Integer>(
new VehicleO, new AmphibianO, "hi". 47);
}
static
FiveTuple<Vehicle.Amphibian.String,Integer.Double> kO { продолжение & return new
Fi veTuple<Vehi cle,Amphi bi an,Stri ng,Integer,Double>(
new VehicleO, new AmphibianO. "hi", 47, 11.1);
}
public static void main(String[] args) {
TwoTuple<String.Integer> ttsi = f; System.out.pri ntln(ttsi);
// ttsi first = "there"; // Ошибка компиляции- final System.out.pri ntln(g); System.out.println(hO); System, out. println(kO);
}
} /* Output: (hi. 47)
(Amphibian@lf6a7b9, hi, 47) (Vehicle@35ce36, Amphibian@757aef, hi, 47) (Vehicle@9cabl6, Amphibian@la46e30, hi, 47, 11.1) *///:-
Спецификация final для public-полей предотвращает их изменение после конструирования (поэтому попытка выполнения команды ttsi.first="there" приводит к ошибке).
Конструкции new получаются немного громоздкими. Позднее в этой главе будет показано, как упростить их при помощи параметризованных методов.
Класс стека
Давайте рассмотрим менее тривиальный пример: реализацию традиционного стека. В главе И была приведена реализация стека на базе LinkedList. В этом примере класс LinkedList уже содержал все методы, необходимые для создания стека. Класс стека строился объединением одного параметризованного класса (Stack<T>) с другим параметризованным классом (LinkedList<T>). Этот пример показывает, что параметризованный тип — такой же тип, как и все остальные (за некоторыми исключениями, о которых речь пойдет позже):-
Вместо того, чтобы использовать LinkedList, мы также могли реализовать собственный механизм хранения связанного списка:
//: generics/LinkedStack java
// Стек, реализованный на базе внутренней структуры
public class LinkedStack<T> {
private static class Node<U> { U item; Node<U> next;
NodeO { item = null; next = null; } Node(U item, NodeO next) { this.item = item; this next = next;
}
boolean end { return item == null && next == null; }
}
private Node<T> top = new Node<T>; // Предохранитель public void push(T item) {
top = new Node<T>(item, top);
}
public Т popО {
Т result = top item; if( itop.endO)
top = top.next; return result;
}
public static void main(String[] args) {
LinkedStack<String> Iss = new LinkedStack<String>; for(String s : "Phasers on stun!".split(" ")) Iss.push(s);
String s;
while((s = Iss.popO) != null) System.out.printin(s);
}
} /* Output-
stun!
on
Phasers *///:-
Внутренний класс Node тоже является параметризованным и имеет собственный параметр типа.
Для определения наличия элементов в стеке в этом примере используется предохранитель (end sentinel). Он создается при конструировании LinkedStack, а затем при каждом вызове push новый объект Node<T> создается и связывается с предыдущим Node<T>. При вызове рор всегда возвращается top.item, после чего текущий объект Node<T> уничтожается и происходит переход к следующему — если только текущим элементом не является предохранитель; в этом случае переход не выполняется. При повторных вызовах рор клиент будет получать null, что свидетельствует об отсутствии элементов в стеке.