public class TwoTuple { public final A first; public final В second;
public TwoTuple(A а, В b) { first = a; second = b; } public String toStringO {
return "(" + first + " + second + ")";
}
} ///:-
Конструктор запоминает сохраняемый объект, а вспомогательная функция toStringO выводит значения из списка. Обратите внимание: кортеж подразумевает упорядоченное хранение элементов.
При первом чтении может показаться, что такая архитектура нарушает общие принципы безопасности программирования на Java. Разве first и second не должны быть объявлены приватными, а обращения к ним осуществляться только из методов getFirst() и getSecond()? Подумайте, какая безопасность реализуется в этом случае: клиент может читать объекты и делать с прочитанными значениями все, что пожелает, но не может изменить first и second. Фактически объявление final делает то же самое, но короче и проще.
Кортежи большей длины создаются посредством наследования. Добавить новый параметр типа несложно:
//: net/mi ndvi ew/uti1/ThreeTuple.java
package net.mi ndvi ew.uti1;
public class ThreeTuple
}
public String toStringO {
return "(" + first + " + second + ", " + third +")";
}
// net/mi ndvi ew/uti1/FourTuple. java package net.mindview.util;
public class FourTuple extends ThreeTuple { public final D fourth; public FourTuple(A а, В b. С с. D d) { super(a. b, c), fourth = d;
}
public String toStringO {
return "(" + first + ", " + second + " + third + " + fourth + ")";
}
} Hill . net/mi ndvi ew/uti1/Fi veTuple.java package net.mindview util;
public class FiveTuple extends FourTuple { public final E fifth;
public FiveTuple(A а. В b. С с. D d. E e) { super(a, b. c. d); fifth = e.
}
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
// Автоматическая упаковка преобразует int в Integer: return new TwoTuple
}
static ThreeTuple
return new ThreeTuple
}
static
FourTuple
new FourTuple
new VehicleO, new AmphibianO, "hi". 47);
}
static
FiveTuple
Fi veTuple
new VehicleO, new AmphibianO. "hi", 47, 11.1);
}
public static void main(String[] args) {
TwoTuple
// 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
Вместо того, чтобы использовать LinkedList, мы также могли реализовать собственный механизм хранения связанного списка:
//: generics/LinkedStack java
// Стек, реализованный на базе внутренней структуры
public class LinkedStack
private static class Node { U item; Node 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
top = new Node
}
public Т popО {
Т result = top item; if( itop.endO)
top = top.next; return result;
}