Java 運行時類型資訊(RTTI)練習題(一),javartti
題目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.javapackage pets;public class Pet{ private static long counter; private long id = counter++; public String toString(){ return getClass().getSimpleName()+"_"+id;}//:pets\\Cat.javapackage pets;public class Cat extends Pet{}//:pets\\EgyptianMau.javapackage pets;public class EgyptianMau extends Cat{}//:pets\\Manx.javapackage pets;public class Manx extends Cat{}//:pets\\Cymric.javapackage pets;public class Cymric extends Manx{}//:pets\\Dog.javapackage pets;public class Dog extends Pet{}//:pets\\Mutt.javapackage pets;public class Mutt extends Dog{}//:pets\\Pug.javapackage pets;public class Pug extends Dog{}//:pets\\Rodent.javapackage pets;public class Rodent extends Pet{}//:pets\\Rat.javapackage pets;public class Rat extends Rodent{}//:pets\\Mouse.javapackage pets;public class Mouse extends Rodent{}//:pets\\Hamster.javapackage pets;public class Hamster extends Rodent{}
2)實現PetCreator類,放在PetCreator.java檔案中。
//:pets\\PetCreator.javapackage 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)); }}/* outputRat_0Manx_1Cymric_2Pug_3Mutt_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>。