Философия Java3
Шрифт:
throw new RuntimeException(e), } catchdllegalAccessException e) {
throw new RuntimeException(e).
}
}
public Pet[] createArray(int size) { Pet[] result = new Pet[size], for(int i = 0. i < size, i++)
result[i] = randomPetO. return result;
}
public ArrayList<Pet> arrayList(int size) {
ArrayList<Pet> result = new ArrayList<Pet>, Collections addAll(result, createArray(size)), return result,
}
} /// ~
Абстрактный метод getTypes поручает производному классу получение списка объектов Class. В качестве типа класса указан «любой
При вызове newlnstance возможны два вида исключений, обрабатываемые в секциях catch за блоком try. Имена исключений достаточно хорошо объясняют суть проблемы (IllegalAccessException — нарушение механизма безопасности Java, в данном случае если конструктор по умолчанию объявлен private).
Определяя субкласс PetCreator, достаточно предоставить список типов Pet, которые должны создаваться с использованием randomPet и других методов. Метод getTypes возвращает ссылку на статический объект List. Реализация с использованием forName выглядит так:
//• typei nfo/pets/ForNameCreator.java package typeinfo pets; import java util *;
public class ForNameCreator extends PetCreator {
private static List<Class<? extends Pet» types =
new ArrayList<Class<? extends Pet». Л Л
продолжение &
II Типы, создаваемые случайным образом, private static StringE] typeNames = { "typeinfo pets.Mutt", "typeinfo pets Pug", "typeinfo pets EgyptianMau", "typeinfo pets.Manx", "typeinfo.pets.Cymric", "typeinfo.pets.Rat", "typeinfo.pets.Mouse", "typeinfo pets.Hamster"
}:
@SuppressWarni ngs("unchecked") private static void loaderO { try {
for(String name : typeNames) types.add(
(Class<? extends Pet>)Class forName(name)). } catch(ClassNotFoundException e) {
throw new RuntimeException(e);
}
}
static { loaderO; }
public List<Class<? extends Pet» types О {return types,} } ///:-
Метод loader создает список List объектов Class с использованием метода Class.forName. При этом может произойти исключение ClassNotFoundException, что вполне понятно — ведь ему передается строка, содержимое которой невозможно проверить на стадии компиляции. При ссылке на эти классы необходимо указывать имя пакета, которому они принадлежат (typeinfo).
Для получения типизованного списка объектов Class требуется преобразование типа, что приводит к выдаче предупреждения на стадии компиляции. Метод loader определяется отдельно и размещается в секции статической инициализации, потому что директива @SuppressWarnings не может располагаться прямо в секции статической инициализации.
Для подсчета объектов Pet нам понадобится механизм подсчета их разных видов. Для этой цели идеально подойдет карта (Map), в которой ключами являются имена типов Pet, а значениями — переменные Integer с количеством Pet. Например, это позволит получать ответы на вопросы типа «сколько
II: typeinfo/PetCount.java II Использование instanceof. import typeinfo.pets.*; import java util.*;
import static net.mindview.util.Print.*,
public class PetCount {
static class PetCounter extends HashMap<String,Integer> { public void count(String type) {
Integer quantity = get(type); if(quantity == null) put(type, 1);
else
put(type, quantity +1),
}
}
public static void
countPets(PetCreator creator) {
PetCounter counter= new PetCounter, for(Pet pet : creator.createArray(20)) { // Подсчет всех объектов Pet: printnb(pet.getClass.getSimpleNameO + " "), if(pet instanceof Pet)
counter.count("Pet"); if(pet instanceof Dog)
counter.count("Dog"); if(pet instanceof Mutt)
counter count("Mutt"), if(pet instanceof Pug)
counter countC'Pug"); if(pet instanceof Cat)
counter.count("Cat"); if(pet instanceof Manx)
counter count("EgyptianMau"); if(pet instanceof Manx)
counter.count("Manx"); if(pet instanceof Manx)
counter.count("Cymric"). if(pet instanceof Rodent)
counter.count("Rodent"), if(pet instanceof Rat)
counter count("Rat"); if(pet instanceof Mouse)
counter.count("Mouse"); if(pet instanceof Hamster)
counter.count("Hamster"),
}
// Вывод результатов подсчета.
printO;
print(counter);
}
public static void main(String[] args) { countPets(new ForNameCreator);
}
} /* Output-
Rat Manx Cymric Mutt Pug Cymric Pug Manx Cymric Rat EgyptianMau Hamster EgyptianMau Mutt
Mutt Cymric Mouse Pug Mouse Cymric
{Pug=3. Cat=9, Hamster=l, Cymric=7, Mouse=2, Mutt=3, Rodent=5, Pet=20, Manx=7,
EgyptianMau=7, Dog=6, Rat=2}
*///:-
В countPets массив случайным образом заполняется объектами Pet с использованием PetCreator. Затем каждый объект Pet в массиве тестируется и подсчи-тывается при помощи instanceof.
У ключевого слова instanceof имеется одно серьезное ограничение: объект можно сравнивать только с именованным типом, но не с объектом Class. Возможно, вам показалось, что в предыдущем примере перебор всех выражений instanceof выглядит неудобно и громоздко, и вы правы. Тем не менее автоматизировать этот процесс невозможно — создать из объектов Class список ArrayList и сравнивать объекты по очереди с каждым его элементом не получится (к счастью, существует альтернативное решение, но это попозже). Впрочем, особенно горевать по этому поводу не стоит — если вам приходится записывать множество проверок instanceof, скорее всего, изъян кроется в архитектуре программы.
Использование литералов class
Если записать пример PetCreator.java с использованием литералов class, программа во многих отношениях становится более понятной:
//• typeinfo/pets/LiteralPetCreator.java // Using class literals package typeinfo pets, import java util.*;
public class LiteralPetCreator extends PetCreator { // Блок try не нужен @SuppressWarnings("unchecked")
public static final List<Class<? extends Pet» all Types = Col 1 ections unmodi fi ableLi st(Arrays.asLi st(