Каждый класс реализует некоторое понятие «счетности». В случае Counting-Generator.Character это повторение символов верхнего и нижнего регистра. Класс CountingGenerator.String использует CountingGenerator.Character для заполнения массива символов, который затем преобразуется в String. Размер массива определяется аргументом конструктора. Обратите внимание на то, что CountingGenerator.String использует базовую конструкцию Generator Следующая тестовая программа использует рефлексию с идиомой вложенных генераторов, что позволяет применять ее для любого набора генераторов, построенного по указанному образцу: //: arrays/GeneratorsTest.java import net.mindview.util.*; public class GeneratorsTest { public static int size = 10; public static void test(Class > surroundingClass) { for(Class > type : surroundingClass.getClassesO) { System.out.print(type.getSimpleName() + ": "); try { Generator > g = (Generator >)type.newInstance(); for(int i = 0; i < size; i++) System.out printf(g.next() + " "); System, out. printlnO; } catch(Exception e) { throw new RuntimeException(e); } } } public static void main(String[] args) { test(CountingGenerator.class); } } /* Output; Double; 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 Float; 0.0 1.0 2.0 3.0 4.0 5.0 6.0 7.0 8.0 9.0 Long; 0 12 3 4 5 6 7 8 9 Integer; 0 1 2 3 4 5 6 7 8 9 Short; 0 12 3 4 5 6 7 8 9 String: abcdefg hijklmn opqrstu vwxyzAB CDEFGHI JKLMNOP QRSTUVW XYZabcd efghijk lmnopqr Character: abcdefghi j Byte: 0 12 3 4 5 6 7 8 9 Boolean: true false true false true false true false true false *///:- Предполагается, что тестируемый класс содержит серию вложенных объектов Generator, каждый из которых имеет конструктор по умолчанию (то есть без аргументов). Рефлексионный метод getClasses() выдает информацию обо всех вложенных классах. Далее метод test() создает экземпляр каждого генератора и выводит результаты, полученные при десятикратном вызове next(). Следующий набор генераторов основан на случайных числах. Так как конструктор Random инициализируется константой, результаты будут повторяться при каждом запуске программы: //: net/mi ndvi ew/uti1/RandomGenerator.java // Генераторы, выдающие случайные значения, package net.mi ndvi ew.uti1; import java.util.*; public class RandomGenerator { private static Random r = hew Random(47); public static class Boolean implements Generator } } public static class Byte implements Generator return (byte)r nextlntO; } } public static class Character implements Generator return CountingGenerator.charsE r nextInt(CountingGenerator.chars.length)], } } public static class String extends CountingGenerator.String { // Подключение случайного генератора Character { eg = new CharacterO; } // Инициализатор public StringO {} public String(int length) { super(1ength), } } public static class Short implements Generator return (short)r.nextlntO. } } public static class Integer implements Generator public Integer(int modulo) { mod = modulo; } public java lang Integer nextO { return r.nextlnt(mod); } } public static class Long implements Generator public Long(int modulo) { mod = modulo; } public java lang.Long nextO { return new java.lang.Long(r nextInt(mod)); } } public static class Float implements Generator // Отсечение до двух разрядов в дробной части, int trimmed = Math.round(r nextFloatO * 100). return ((float)trimmed) / 100. } } ///:- Как видите, RandomGenerator.String наследует от CountingGenerator.String, просто подключая новый генератор Character. Чтобы генерируемые числа были не слишком велики, RandomGenerator. Integer по умолчанию берет остаток от деления на 10 ООО, но перегруженный конструктор позволяет выбрать меньшее значение. Аналогичный подход используется и для RandomGenerator.Long. Для генераторов Float и Double цифры в дробной части усекаются. Для тестирования RandomGenerator можно воспользоваться уже готовым классом GeneratorsTest: //: arrays/RandomGeneratorsTest.java import net.mindview util.*; public class RandomGeneratorsTest { public static void main(String[] args) { GeneratorsTest test(RandomGenerator.class); } } /* Output: Double: 0.73 0.53 0.16 0 19 0.52 0.27 0.26 0.05 0.8 0.76 Float: 0.53 0,16 0.53 0.4 0.49 0.25 0.8 0.11 0.02 0.8 Long: 7674 8804 8950 7826 4322 896 8033 2984 2344 5810 Integer: 8303 3141 7138 6012 9966 8689 7185 6992 5746 3976 Short: 3358 20592 284 26791 12834 -8092 13656 29324 -1423 5327 String: bklnaMe sbtWHkj UrUkZPg wsqPzDy CyRFJQA HxxHvHq XumcXZJ oogoYWM NvqeuTp nXsgqia Character: xxEAJJmzMs Byte: -60 -17 55 -14 -5 115 39 -37 79 115 Boolean: false true false false true true true true true true *///:- Чтобы изменить количество генерируемых значений, воспользуйтесь public-полем GeneratorsTest.size. Создание массивов с использованием генераторов Для создания массивов на основе Generator нам потребуются два вспомогательных класса. Первый использует произвольный Generator для получения массива типов, производных от Object. Для решения проблемы с примитивами второй класс получает произвольный массив с объектами-«обертками» и строит для него соответствующий массив примитивов. Первый вспомогательный класс может работать в двух режимах, представленных перегруженным статическим методом аггау(). Первая версия метода получает существующий массив и заполняет его с использованием Generator; вторая версия получает объект Class, Generator и количество элементов и создает новый массив, который также заполняется с использованием Generator. Помните, что при этом создаются только массивы субтипов Object, но не массивы примитивных типов: