Рейтинговые книги
Читем онлайн Философия Java3 - Брюс Эккель

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 82 83 84 85 86 87 88 89 90 ... 132

Вспомогательный класс Set

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

//: net/mi ndvi ew/uti1/Sets.java package net.mindview.util; import java.util.*;

public class Sets {

public static <T> Set<T> union(Set<T> a, Set<T> b) { Set<T> result = new HashSet<T>(a);

result.addAl1(b). return result;

}

public static <T>

Set<T> intersection(Set<T> a. Set<T> b) { Set<T> result = new HashSet<T>(a). result retainAll(b); return result;

}

// Вычитание подмножества из надмножества-public static <T> Set<T> difference(Set<T> superset. Set<T> subset) {

Set<T> result = new HashSet<T>(superset); result.removeAll(subset). return result;

}

// Дополнение -- все. что не входит в пересечение public static <T> Set<T> complement(Set<T> a, Set<T> b) {

return difference(union(a. b). intersection^, b));

}

} ///:-

Первые три метода дублируют первый аргумент, копируя его ссылки в новый объект HashSet, поэтому аргументы Set не изменяются напрямую. Таким образом, возвращаемое значение представляет собой новый объект Set.

Четыре метода представляют математические операции с множествами: union() возвращает объект Set, полученный объединением множеств-аргументов, intersection() возвращает объект Set с общими элементами аргументов, difference() вычисляет разность множеств, a complement) — объект Set со всеми элементами, не входящими в пересечение. Чтобы создать простой пример использования этих методов, мы воспользуемся перечислением, содержащим разные названия акварельных красок:

//: generics/watercolors/Watercolors java package generics.watercolors;

public enum Watercolors {

ZINC. LEM0N_YELL0W. MEDIUM_YELLOW, DEEP_YELLOW, ORANGE. BRILLIANT_RED. CRIMSON. MAGENTA. ROSE_MADDER. VIOLET. CERULEAN_BLUE_HUE. PHTHALO_BLUE, ULTRAMARINE. COBALT_BLUE_HUE, PERMANENT_GREEN. VIRIDIAN_HUE. SAP_GREEN. YELL0W_0CHRE. BURNT_SIENNA. RAWJJMBER, BURNTJJMBER. PAYNES_GRAY. IVORY_BLACK } ///:-

Для удобства (чтобы избежать уточнения всех имен) в следующем примере это перечисление импортируется статически. Мы используем EnumSet — новый инструмент Java SE5 для простого создания Set на базе перечисления. Статическому методу EnumSet.range() передаются первый и последний элементы диапазона, по которому строится множество:

II: generics/WatercolorSets.java import generics.watercolors.*; import java.util.*;

import static net.mindview.util.Print.*; продолжение &

import static net.mindview util.Sets *; import static generics.watercolors.Watercolors.*;

public class WatercolorSets {

public static void main(String[] args) { Set<Watercolors> setl =

EnumSet.range(BRILLIANT_RED, VIRIDIAN_HUE); Set<Watercolors> set2 =

EnumSet range(CERULEAN_BLUE_HUE, BURNT_UMBER), printCsetl. " + setl); print("set2- " + set2);

print("union(setl. set2)- " + union(setl. set2)); Set<Watercolors> subset = intersection(setl. set2); print("intersection(setl. set2). " + subset). print("difference(setl. subset)- " +

difference(setl. subset)). print("difference(set2. subset). " +

difference(set2. subset)); print("complement(setl. set2) " + complement(setl. set2));

}

} /* Output.

setl. [BRILLIANT_RED. CRIMSON. MAGENTA. ROSE_MADDER, VIOLET. CERULEAN_BLUE_HUE. PHTHALO_BLUE. ULTRAMARINE. COBALT_BLUE_HUE. PERMANENT_GREEN. VIRIDIAN_HUE] set2- [CERULEAN_BLUE_HUE, PHTHALO_BLUE. ULTRAMARINE. COBALT_BLUE_HUE. PERMANENT_GREEN. VIRIDIAN_HUE. SAP_GREEN. YELL0W_0CHRE. BURNT_SIENNA. RAWJJMBER. BURNT_UMBER] union(setl. set2) [SAP_GREEN. ROSE_MADDER, YELL0W_0CHRE. PERMANENT_GREEN. BURNTJJMBER, COBALT_BLUE_HUE, VIOLET. BRILLIANT_RED. RAWJJMBER. ULTRAMARINE. BURNT_SIENNA. CRIMSON. CERULEAN_BLUE_HUE. PHTHALO_BLUE. MAGENTA. VIRIDIAN_HUE]

intersection(setl. set2): [ULTRAMARINE. PERMANENT_GREEN. COBALT_BLUE_HUE. PHTHALO_BLUE. CERULEAN_BLUE_HUE. VIRIDIAN_HUE]

difference(setl, subset): [ROSE_MADDER, CRIMSON. VIOLET. MAGENTA. BRILLIANT_RED] difference(set2. subset): [RAWJJMBER, SAP_GREEN. YELLOW J3CHRE, BURNT_SIENNA, BURNTJJMBER]

complement(setl, set2): [SAP_GREEN. ROSE_MADDER. YELL0W_0CHRE. BURNTJJMBER, VIOLET. BRILLIANT_RED, RAW_UMBER. BURNT_SIENNA. CRIMSON. MAGENTA] *///:-

В выходных данных показаны результаты выполнения каждой операции. В следующем примере представлены варианты вызова Sets.difference() для разных классов Collection и Map из java.util:

//: net/mi ndvi ew/uti1/Contai nerMethodDi fferences.java package net.mindview.util; import java lang reflect *; import java.util.*,

public class ContainerMethodDifferences {

static Set<String> methodSet(Class<?> type) {

Set<String> result = new TreeSet<String>(); for (Method m : type.getMethodsO) result.add(m.getNameO); return result;

}

static void interfaces(Class<?> type) {

System.out.print("Interfaces in " +

type getSimpleNameO + ": "); List<String> result = new ArrayList<String>();

for(Class<?> с : type.getlnterfacesO) result.add(c.getSimpleName()); System.out.println(result);

}

static Set<String> object = methodSet(Object.class); static { object.add("clone"); } static void

differencesass<?> superset, Class<?> subset) {

System.out.pri nt(superset.getSimpleName() +

" extends " + subset.getSimpleNameO + ", adds: "); Set<String> comp = Sets.difference(

methodSet(superset). methodSet(subset)); сотр.removeAll(object); // He показывать методы 'Object' System.out.println(comp); interfaces(superset),

}

public static void main(String[] args) {

System.out.printlnC'Collection: " +

methodSet(Collection.class)), interfaces(Collection.class); difference(Set.class. Collection.class); difference(HashSet.class. Set.class); difference(LinkedHashSet.class, HashSet.class); difference(TreeSet.class. Set.class); differences st. class. Col 1 ecti on.cl ass); difference(ArrayList.class, List.class); differences nkedLi st. class. List.class); difference(Queue.class. Collection.class); di fference(Pri ori tyQueue.class. Queue.class); System.out.println("Map: " + methodSet(Map.class)); difference(HashMap.class. Map.class); difference(LinkedHashMap.class. HashMap.class); difference(SortedMap.class. Map.class); difference(TreeMap.class, Map class);

}

} ///:-

Анонимные внутренние классы

Параметризация также может применяться к внутренним классам и анонимным внутренним классам. Пример реализации интерфейса Generator с использованием анонимных внутренних классов:

//: generics/BankTeller.java

II Очень простая имитация банковского обслуживания.

import java.util.*;

import net.mindview.util.*;

class Customer {

private static long counter = 1; private final long id = counter++; private Customer() {}

public String toStringO { return "Customer " + id; } // Метод для получения объектов Generator: public static Generator<Customer> generatorO { return new Generator<Customer>()

public Customer nextO { return new CustomerO; }

class Teller {

private static long counter = 1; private final long id = counter++; private TellerO {}

public String toStringO { return "Teller " + id; } // Синглетный объект Generator: public static Generator<Teller> generator = new Generator<Teller>() {

public Teller next О { return new TellerO; }

}:

}

public class BankTeller {

public static void serve(Teller t, Customer c) {

System.out.printin(t + " обслуживает " + с);

}

public static void main(String[] args) { Random rand = new Random(47); Queue<Customer> line = new LinkedList<Customer>(); Generators.fillOine, Customer, generator 0, 15): List<Teller> tellers = new ArrayList<Teller>(); Generators.filKtellers, Teller.generator, 4); for(Customer с : line)

serve(tellers.get(rand.nextlnt(tellers.size())), c);

}

} /* Output:

Teller

3

обслуживает

Customer

1

Teller

2

обслуживает

Customer

2

Teller

3

обслуживает

Customer

3

Teller

1

обслуживает

Customer

4

Teller

1

обслуживает

Customer

5

Teller

3

обслуживает

Customer

6

Teller

1

обслуживает

Customer

7

Teller

2

обслуживает

Customer

8

Teller

3

обслуживает

Customer

9

Teller

3

обслуживает

Customer

10

Teller

2

обслуживает

Customer

11

Teller

4

обслуживает

Customer

12

Teller

2

обслуживает

Customer

13

Teller

1

обслуживает

Customer

14

Teller

1

обслуживает

Customer

15

*///•-

И Customer, и Teller содержат приватные конструкторы, поэтому для создания их объектов пользователь вынужден использовать объекты Generator. Customer содержит метод generator(), который при каждом вызове создает новый объект Generator<Customer>. На случай, если множественные объекты Generator вам не понадобятся, в Teller создается синглетный открытый объект generator. Оба подхода продемонстрированы в вызовах fill() внутри main().

Поскольку метод generator() в Customer и объект Generator в Teller являются статическими, они не могут быть частью интерфейса, поэтому «обобщить» эту"

конкретную идиому не удастся. Несмотря на это обстоятельство, она достаточно хорошо работает в методе fill().

Построение сложных моделей

К числу важных преимуществ параметризации относится простота и надежность создания сложных моделей. Например, можно легко создать список (List) с элементами-кортежами:

//: generics/TupleList.java

// Построение сложных параметризованных типов путем объединения

import java.util.*;

import net.mindview util.*;

public class TupleList<A,B.C.D> extends ArrayList<FourTuple<A,B,C.D» {

public static void main(String[] args) {

TupleList<Vehicle, Amphibian. String. Integer> tl =

new TupleList<Vehicle. Amphibian, String. Integer>(); tl.add(TupleTest.hO); tl.add(TupleTest.hO):

for(FourTuple<Vehicle.Amphibian.String.Integer> v tl) System.out.println(i);

}

} /* Output:

([email protected] [email protected], hi. 47) ([email protected], [email protected] hi. 47) *///.-

Запись получается довольно громоздкой (особенно при создании итератора), однако вы получаете довольно сложную структуру данных без излишков программного кода.

А вот другой пример, который показывает, как легко строить сложные модели на основе параметризованных типов. Хотя каждый класс представляет собой автономный «строительный блок», их совокупность имеет сложную структуру. В данном случае моделируется магазин с товарами, полками и стеллажами:

//. generics/Store.java

// Построение сложной модели на базе параметризованных контейнеров, import java util *. import net.mindview.util.*.

class Product {

private final int id. private String description; private double price;

public Product(int IDnumber, String descr. double price){ id = IDnumber; description = descr, this.price = price; System.out.pri ntln(toString());

}

public String toStringO {

return id + " + description + ", цена: $" + price;

public void priceChange(double change) { price += change,

}

public static Generator<Product> generator = new Generator<Product>() {

private Random rand = new Random(47), public Product next О {

return new Product(rand nextlnt(lOOO), "Test",

Math round(rand nextDoubleO * 1000 0) + 0 99).

class Shelf extends ArrayList<Product> { public Shelf(int nProducts) {

Generators fill(this. Product generator. nProducts),

class Aisle extends ArrayList<Shelf> {

public AisleCint nShelves, int nProducts) { for(int i = 0; i < nShelves; i++) add(new Shelf(nProducts)),

class CheckoutStand {} class Office {}

public class Store extends ArrayList<Aisle> {

private ArrayList<CheckoutStand> checkouts =

new ArrayList<CheckoutStand>(); private Office office = new OfficeO. public Store(int nAisles, int nShelves, int nProducts) { for(int i = 0; i < nAisles; i++)

1 ... 82 83 84 85 86 87 88 89 90 ... 132
На этой странице вы можете бесплатно читать книгу Философия Java3 - Брюс Эккель бесплатно.
Похожие на Философия Java3 - Брюс Эккель книги

Оставить комментарий