如何确保使用子类参数调用的方法与泛型Class对象一起工作



例如,我得到了3个类:

超类:Animal

子类扩展超类:CatTiger

我编写了一个检查器类AnimalChecker来区分动物的类型,并使每个类型调用不同的方法(不同类型的参数,相同的方法名称)。如果使用C++模板,就有可能完成这类工作,想知道他们用Java使其工作的简单方法是什么,我做了一些尝试,但还没有得到。:

AnimalChecker定义如下:

public abstract class AnimalChecker {
    private List<Class<? extends Animal>> mAnimals;
    public AnimalChecker(Class<? extends Animal>... animals) {
        mAnimals = Arrays.asList(animals);
    }
    public boolean CheckAnimal(Animal animal) {
        Iterator<Class<? extends Animal>> it = mAnimals.iterator();
        while (it.hasNext()) {
            Class clazz = it.next();
            if (clazz.isInstance(animal)) {
                onCheck(animal, clazz);
                return true;
            }
        }
        return false;
    }
    public abstract void onCheck(Animal animal, Class<? extends Animal> clazz);
}

然后我尝试实现这个类,为每种类型做具体的工作:

public class Main {
    public static MyChecker msChecker = new MyChecker();
    public static void main(String[] args) {
        AnimalChecker checker = new AnimalChecker(Cat.class, Tiger.class) {
            @Override
            public void onCheck(Animal animal, Class<? extends Animal> clazz) {
                System.out.println(clazz.toGenericString());
                msChecker.onCheck(clazz.cast(animal));
            }
        };
        checker.CheckAnimal(new Tiger());
        checker.CheckAnimal(new Cat());
        MyChecker myChecker = new MyChecker();
        myChecker.onCheck(new Tiger());
        myChecker.onCheck(new Cat());
    }
    static class MyChecker {
        public void onCheck(Animal animal) {
            System.out.println("Animal");
        }
        public void onCheck(Cat animal) {
            System.out.println("Cat");
        }
        public void onCheck(Tiger animal) {
            System.out.println("Tiger");
        }
    }
}

下面的输出不是我想要的:

public class test.Tiger
Animal
public class test.Cat
Animal
Tiger
Cat

我想把结果做成

public class test.Tiger
Tiger
public class test.Cat
Cat
Tiger
Cat

Java不会为您做这件事,非常简单。您试图让Java执行的操作称为多重调度,Java不支持它。方法参数的类型只在编译时由编译器与参数值匹配,而不是在运行时。在代码中,编译器对参数值最具体的了解是它的类型为Animal,因此它选择链接到该方法。clazz.cast()调用没有帮助,因为相同的参数适用于clazz变量:编译器对它最具体的了解是它是? extends Animal,因此就编译器而言,cast()调用的结果属于Animal类型。

当然,在Java中有一些方法可以达到类似的效果,但我不认为我可以为您选择一种。上面链接的维基百科文章中有一个关于多重调度的例子,你可能也想考虑类似于访问者模式的东西,但不要觉得被模式束缚了。:)

最新更新