Java 运行时类型信息(RTTI)练习题(一)
题目1:实现如下图所示的类及其结构,Pet是基类,Cat、Dog和Rodent直接继承Pet,余下的其他类分别继承自各自的超类。基类Pet为每个实例(包括子类的实例)自动生成一个不重复的编码,储存在私有域long id中。基类Pet重载toString()函数,返回类型名+编号。
实现PetCreator类,1)实现公共方法返回指向随机的Pet子类对象的引用,2)实现公共方法返回填充随机Pet子类对象的数组,3)实现公共方法返回填充随机Pet子类对象的List。
解答1:
1)创建Pet及其子类,为每个类单独编写一个.java文件。
//:pets\\Pet.java package pets; public class Pet{ private static long counter; private long id = counter++; public String toString(){ return getClass().getSimpleName()+"_"+id; } //:pets\\Cat.java package pets; public class Cat extends Pet{} //:pets\\EgyptianMau.java package pets; public class EgyptianMau extends Cat{} //:pets\\Manx.java package pets; public class Manx extends Cat{} //:pets\\Cymric.java package pets; public class Cymric extends Manx{} //:pets\\Dog.java package pets; public class Dog extends Pet{} //:pets\\Mutt.java package pets; public class Mutt extends Dog{} //:pets\\Pug.java package pets; public class Pug extends Dog{} //:pets\\Rodent.java package pets; public class Rodent extends Pet{} //:pets\\Rat.java package pets; public class Rat extends Rodent{} //:pets\\Mouse.java package pets; public class Mouse extends Rodent{} //:pets\\Hamster.java package pets; public class Hamster extends Rodent{}
2)实现PetCreator类,放在PetCreator.java文件中。
//:pets\\PetCreator.java package pets; import java.util.*; public class PetCreator{ public Pet getRandomPet() throws Exception { return types.get(rand.nextInt(types.size())).newInstance(); } public Pet[] getRandomPetArray(int size) throws Exception{ Pet[] pets = new Pet[size]; for(int i = 0; i < size; i++){ pets[i] = getRandomPet(); } return pets; } public List<Pet> getRandomPetList(int size) throws Exception{ List<Pet> pets = new LinkedList<Pet>(); for(int i = 0; i < size; i++){ pets.add(getRandomPet()); } return pets; } private Random rand = new Random(47); private static final String typeNames[] = { "pets.Pug", "pets.Mutt", "pets.EgyptianMau", "pets.Manx", "pets.Cymric", "pets.Rat", "pets.Mouse", "pets.Hamster" }; private static List<Class<? extends Pet>> types = new ArrayList<Class<? extends Pet>>(); static{ loader(); } @SuppressWarnings("unchecked") private static void loader(){ for(String name : typeNames){ try{ types.add((Class<? extends Pet>) Class.forName(name)); }catch(ClassNotFoundException e){ e.printStackTrace(); throw new RuntimeException(); } } } public static void main(String[] args) throws Exception { PetCreator pc = new PetCreator(); for(int i = 0; i < 5; i++){ System.out.println(pc.getRandomPet()); } System.out.println(Arrays.toString(pc.getRandomPetArray(5))); System.out.println(pc.getRandomPetList(5)); } } /* output Rat_0 Manx_1 Cymric_2 Pug_3 Mutt_4 [Cymric_5, Mutt_6, Manx_7, Cymric_8, Rat_9] [EgyptianMau_10, Hamster_11, EgyptianMau_12, Pug_13, Pug_14] */
分析:
- 基类Pet的toString()方法中调用的getName()方法在编译时会动态绑定为子类相应的方法。
- 对Class对象应用泛型与通常的泛型规则不同。比如对List接口应用泛型,由List<Pet>引用指向的List对象可以存入任意Pet子类的引用,但Class<Pet>的引用却无法指向Pet子类的Class对象。这是因为虽然Pet子类继承自Pet,但Pet子类的Class对象并不是Pet类的Class对象的子类。因此对Class对象应用泛型需要用通配符(wildcard)。比如定义可以指向任意Pet子类的Class对象的引用的语句为Class<? extends Pet>。