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

ЖАНРЫ

Философия Java3

Эккель Брюс

Шрифт:

return storage.get(rand.nextInt(storage.si ze));

}•

public static void main(String[] args) {

RandomList<String> rs = new RandomList<String>; for(String s: ("The quick brown fox jumped over " + "the lazy brown dog").splitC "))

rs. add (s); продолжение & for(int i = 0; i < 11; i++)

System.out.printers.select О + " ");

}

} /* Output:

brown over fox quick quick dog brown The brown lazy brown

Параметризованные интерфейсы

Параметризация

работает и с интерфейсами. Например, класс, создающий объекты, называется генератором. В сущности, генератор представляет собой специализированную версию паттерна «метод-фабрика», но при обращении к нему никакие аргументы не передаются, тогда как метод-фабрика обычно получает аргументы. Генератор умеет создавать объекты без дополнительной информации.

Обычно генератор определяет всего один метод — тот, который создает объекты. Назовем его next и включим в стандартный инструментарий:

//• net/mi ndvi ew/uti1/Generator.java

// Параметризованный интерфейс

package net.mi ndvi ew.uti1;

public interface Generator<T> { T nextO; } ///:-

Возвращаемое значение метода next параметризовано по типу Т. Как видите, механизм параметризации работает с интерфейсами почти так же, как с классами.

Чтобы продемонстрировать, как работает реализация Generator, мы воспользуемся иерархией классов, представляющих разные виды кофе:

//: generics/coffee/Coffee.java package generics.coffee;

public class Coffee {

private static long counter = 0; private final long id = counter**; public String toStringO {

return getClassO.getSimpleNameО + " " + id:

}

} Hill-. generics/coffee/Latte.java package generics.coffee; public class Latte extends Coffee {} Hill \ generics/coffee/Mocha.java package generics.coffee; public class Mocha extends Coffee {} Hill : generics/coffee/Cappuccino.java package generics.coffee; public class Cappuccino extends Coffee {} Hill : generics/coffee/Americano.java package generics.coffee;

public class Americano extends Coffee {} /// ~

//. generics/coffee/Breve java

package generics coffee.

public class Breve extends Coffee {} ///:-

Теперь мы можем реализовать интерфейс Generator<Coffee>, который создает случайные типы объектов из иерархии Coffee:

// generics/coffee/CoffeeGenerator.java

// Генератор случайных объектов из иерархии Coffee-

package generics coffee.

import java util *,

import net mindview util.*,

public class CoffeeGenerator

implements Generator<Coffee>, Iterable<Coffee> {

private Class[] types = { Latte class. Mocha.class.

Cappuccino class, Americano.class. Breve class. }; private static Random rand = new Random(47); public CoffeeGeneratorО {} //Для перебора-private int size = 0.

public CoffeeGenerator(int sz) { size = sz;' } public Coffee next О { try {

return (Coffee)

types[rand nextInt(types.length)] newlnstance. //

Сообщение об ошибках во время выполнения: } catch(Exception е) {

'throw new RuntimeException(e);

}

}

class Coffeelterator implements Iterator<Coffee> { int count = size;

public boolean hasNextO { return count > 0. } public Coffee next О { count--;

return CoffeeGenerator.this.next.

}

public void removeO { // He реализован

throw new UnsupportedOperationExceptionO;

}

}:

public Iterator<Coffee> iteratorO { return new CoffeeIterator;

}

public static void main(String[] args) {

CoffeeGenerator gen = new CoffeeGenerator; for (int i =0. i <5; i++)

System.out println(gen.nextO); for(Coffee с : new CoffeeGenerator(5)) System.out println(c),

}

} /* Output-Americano 0 Latte 1

Americano 2 продолжение &

Mocha 3 Mocha 4 Breve 5 Americano 6 Latte 7 Cappuccino 8 Cappuccino 9 *///:-

Параметризованный интерфейс Generator гарантирует, что next вернет параметр типа. CoffeeGenerator также реализует интерфейс Iterable и поэтому может использоваться в синтаксисе foreach. Аргумент, по которому определяется момент прекращения перебора, передается при вызове второго конструктора.

А вот как выглядит другая реализация Generator<T>, предназначенная для получения чисел Фибоначчи:

//. generics/Fibonacci java // Построение чисел Фибоначчи import net mindview util *;

public class Fibonacci implements Generator<Integer> { private int count = 0;

public Integer nextO { return fib(count++); } private int fibCint n) {

if(n < 2) return 1, return fib(n-2) + fib(n-l),

}

public static void main(String[] args) { Fibonacci gen = new Fibonacci; for(int i = 0; i < 18: i++)

System.out.print(gen.nextО + " ");

}

} /* Output-

1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 *///:-

Хотя и внутри, и снаружи класса мы работаем с int, в параметре типа передается Integer. В этом проявляется одно из ограничений параметризации в языке Java: примитивные типы не могут использоваться в качестве параметров типа. Впрочем, в Java SE5 была добавлена удобная автоматическая упаковка (распаковка) для перехода от примитивных типов к объектным «оберткам», и наоборот.

Можно сделать следующий шаг вперед и создать генератор чисел Фибоначчи с реализацией Iterable. Конечно, можно изменить реализацию класса и добавить интерфейс Iterable, но исходные коды не всегда находятся в вашем распоряжении, и вообще там, где это возможно, лучше обойтись без их модификации. Вместо этого мы воспользуемся «адаптером» для получения нужного интерфейса (этот паттерн уже упоминался ранее в книге).

Существует несколько вариантов реализации адаптеров. Например, для получения адаптируемого класса можно воспользоваться наследованием:

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