Чтение онлайн

ЖАНРЫ

Философия Java3

Эккель Брюс

Шрифт:

Кортежи большей длины создаются посредством наследования. Добавить новый параметр типа несложно:

//: net/mi ndvi ew/uti1/ThreeTuple.java

package net.mi ndvi ew.uti1;

public class ThreeTuple<A.B,C> extends TwoTuple<A,B> { public final С third; public ThreeTuple(A а, В b, С с) { super(a. b); third = c:

}

public String toStringO {

return "(" + first + " + second + ", " + third +")";

}

// net/mi ndvi ew/uti1/FourTuple. java package net.mindview.util;

public class FourTuple<A,B,C,D> extends ThreeTuple<A,B,C> { 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<A,B,C,D,E> extends FourTuple<A,В,C.D> { 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<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, что свидетельствует об отсутствии элементов в стеке.

RandomList

Рассмотрим еще один пример контейнера: допустим, вам понадобилась особая разновидность списка, которая случайным образом выбирает один из своих элементов при вызове select. Так как класс должен работать для любых объектов, мы воспользуемся параметризацией:

//• generics/RandomList.java import java.util.*;

public class RandomList<T> {

private ArrayList<T> storage'= new ArrayList<T>, private Random rand = new Random(47); public void add(T item) { storage.add(item); } public T selectО {

Поделиться с друзьями: