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>。

posted on 2017-02-23 13:59  流动的空气  阅读(397)  评论(0编辑  收藏  举报

导航