简体   繁体   中英

How to ensure method called with subclass param work with generic Class object?

For example, I got 3 classes:

Superclass: Animal

Subclass extend Superclass: Cat , Tiger .

I Wrote a checker class, AnimalChecker to distinguish the type of animal, and make each type call different method(different type of param, same method name). If using C++ template, it is possible to do this kind of work, wonder to know is their simple way to make it work with Java , I did some tries but not get it yet. :

AnimalChecker defined below:

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);
}

Then I tried implement the class, do the specific work for each type:

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");
        }
    }
}

The output below isn't what I want:

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

I wanna to make the result

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

Java will not do this for you, quite simply. What you are trying to make Java do is called multiple dispatch , and Java does not support it. The types of method arguments are only matched against argument values at compile-time, by the compiler, not at runtime. In your code, the most specific thing the compiler knows about your argument value is that it is of type Animal , and therefore it chooses to link to that method. The clazz.cast() call doesn't help, since the same argument applies to the clazz variable: the most specific thing the compiler knows about it is that it is ? extends Animal ? extends Animal , and therefore the result of the cast() call is of type Animal as far as the compiler is concerned.

There are, of course, ways for you to achieve similar effects in Java, but I don't think I can choose one for you. There is one example in the above linked Wikipedia article on multiple dispatch, and you may also want to consider something akin to the visitor pattern , but don't feel bound by patterns. :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM