检查数组中的元素是否是Java中的SubClass

时间:2022-09-27 21:22:22

let's assume that I want to check if values within an Object array are of the superclass or subclass let's say for instance that my super class is Called Animal, I declare an array of type Animal

让我们假设我想检查一个Object数组中的值是否属于超类或子类,例如我的超类叫Called Animal,我声明一个类型为Animal的数组

Animal myAnimals[] = new Animal[];

Now suppose that there are subclasses of Animal like Lion, Tiger, Elephant, etc. If I were to loop through an array, how would I differentiate the subclasses (Lion, Tiger, etc.) from the superclass Animal? Thanks!

现在假设有像Lion,Tiger,Elephant等动物的子类。如果我要遍历数组,我如何区分子类(Lion,Tiger等)和超类Animal?谢谢!

3 个解决方案

#1


6  

Using instanceof

At run time, the result of the instanceof operator is true if [...] the reference could be cast (§15.16) to the ReferenceType without raising a ClassCastException.

在运行时,如果引用可以在不引发ClassCastException的情况下将引用(第15.16节)强制转换为ReferenceType,则instanceof运算符的结果为true。

for (Animal a : myAnimals) {
    if (a instanceof Lion) System.out.println("Lion");
    // etc.
}

#2


1  

You could iterate every element and check the subtype by using instanceof..

您可以迭代每个元素并使用instanceof检查子类型。

#3


1  

As @YassinHajaj already said you can use the instanceof operator:

正如@YassinHajaj已经说过你可以使用instanceof运算符:

 for (Animal animal : animals) {

     if (animal instanceof Tiger) {

           Tiger tiger = (Tiger) animal;
     }
 }

However this results in unstructured code, besides this is hard to maintain. I personally prefer an more object oriented way.

然而,这导致非结构化代码,此外这很难维护。我个人更喜欢更面向对象的方式。

As @JBNizet suggested in a comment you can use polymorphism. That's good but not perfect: you will need to change the implementation of all animal classes in order to add some logic.

正如@JBNizet在评论中建议的那样,你可以使用多态。这很好但不完美:你需要改变所有动物类的实现以增加一些逻辑。


Visitor pattern

However if you combine this with the visitor pattern. This will become very powerful because you can separate the logic into a visitor class:

但是,如果将此与访问者模式结合使用。这将变得非常强大,因为您可以将逻辑分成访问者类:

interface AnimalVisitor {

    void visitLion(Lion lion);
    void visitFish(Fish fish);

    // Gets called when animal does not override the accept method:
    void visitDefault(Animal animal); 
}

class Animal {

    public void accept(AnimalVisitor visitor) {
        visitor.visitDefault(this);
    }
}

class Fish extends Animal {

    @Override
    public void accept(AnimalVisitor visitor) {
        visitor.visitFish(this);
    }
}

class Lion extends Animal {

    @Override
    public void accept(AnimalVisitor visitor) {
        visitor.visitLion(this);
    }
}

Then you can easily replace your loop with something like this:

然后你可以用这样的东西轻松替换你的循环:

AnimalVisitor visitor = new AnimalVisitor() {

    @Override
    public void visitLion(Lion lion) {
        // Do something with lion
    }

    @Override
    public void visitFish(Fish fish) {
        // Do something with fish
    }
}

for (Animal animal : animals) {
    animal.accept(visitor);
}

We can even take this one step further:

我们甚至可以更进一步:

Reflective visitors

Since it is annoying to add for every different kind of animal an specific visitAnimal method, we can make use of reflection to avoid this! This will result in smaller and cleaner code:

由于为每种不同种类的动物添加特定的visitAnimal方法很烦人,我们可以利用反射来避免这种情况!这将导致更小更清晰的代码:

interface Visitable { }

class Animal implements Visitable {

    // No accept method
}

class Fish extends Animal {}
class Goldfish extends Fish {}
class Shark extends Fish {}


// Take for example this visitor:

class BittenByVisitor extends ReflectiveVisitor {


    private Surfer surfer;

    public BitByVisitor(surfer) {
        this.surfer = surfer;
    }

    // We only care about the sharks:

    public void visit(Shark shark) {

        surfer.die();
    }


    // Any other fish is just the same:

    public void visit(Fish fish) {

        surface.decreaseHealthBy(1);
    }

    // It also works with interfaces:
    public void visit(VerySmallFish fish) {

        // Do nothing by purpose!
    }
}

And here an implementation of the reflective visitor:

这里是反思访客的实现:

abstract class ReflectiveVisitor {

    public void visit(Visitable v) throws NoSuchMethodException {
        Method m = findMethod(v);

        try {
            m.invoke(this, new Object[] { v });
        }

        catch ( IllegalAccessException e1 ) { /* code handling */ }
        catch ( InvocationTargetException e2 ) { /* code handling */ }
    }

    private Method findMethod(Visitable v) throws NoSuchMethodException {

        String methodName = "visit";
        Class visitable = v.getClass();

        while ( isAncestorOf("Visitable", visitable) {

            Class visitor = getClass();

            while ( isAncestorOf("Visitor", visitor) {

                try {
                    Method m = visitor.getDeclaredMethod(methodName, new Class[]{visitable});
                    return m;
                } catch ( NoSuchMethodException e ) {
                    visitor = visitor.getSuperclass();
                }
            }

            visitable = visitable.getSuperclass();
        }

        String errMsg = "put error message here";
        throw new NoSuchMethodException(errMsg);
    }

    private boolean isAncestorOf(String ancestorName, Class descendant) {

        try {
            return Class.forName(ancestorName).isAssignableFrom(descendant);
        }
        catch ( ClassNotFoundException e ) { /* code handling */ }
            return false;
        }
    }
}

Source code is taken from this paper.

源代码摘自本文。

I personally like to use a reflective visitor which avoids the Visitable class. You can define it like this:

我个人喜欢使用反射访问者来避​​免Visitable类。您可以这样定义:

class ReflectiveVisitor<T> {

    public void visit(T visitable);
}

#1


6  

Using instanceof

At run time, the result of the instanceof operator is true if [...] the reference could be cast (§15.16) to the ReferenceType without raising a ClassCastException.

在运行时,如果引用可以在不引发ClassCastException的情况下将引用(第15.16节)强制转换为ReferenceType,则instanceof运算符的结果为true。

for (Animal a : myAnimals) {
    if (a instanceof Lion) System.out.println("Lion");
    // etc.
}

#2


1  

You could iterate every element and check the subtype by using instanceof..

您可以迭代每个元素并使用instanceof检查子类型。

#3


1  

As @YassinHajaj already said you can use the instanceof operator:

正如@YassinHajaj已经说过你可以使用instanceof运算符:

 for (Animal animal : animals) {

     if (animal instanceof Tiger) {

           Tiger tiger = (Tiger) animal;
     }
 }

However this results in unstructured code, besides this is hard to maintain. I personally prefer an more object oriented way.

然而,这导致非结构化代码,此外这很难维护。我个人更喜欢更面向对象的方式。

As @JBNizet suggested in a comment you can use polymorphism. That's good but not perfect: you will need to change the implementation of all animal classes in order to add some logic.

正如@JBNizet在评论中建议的那样,你可以使用多态。这很好但不完美:你需要改变所有动物类的实现以增加一些逻辑。


Visitor pattern

However if you combine this with the visitor pattern. This will become very powerful because you can separate the logic into a visitor class:

但是,如果将此与访问者模式结合使用。这将变得非常强大,因为您可以将逻辑分成访问者类:

interface AnimalVisitor {

    void visitLion(Lion lion);
    void visitFish(Fish fish);

    // Gets called when animal does not override the accept method:
    void visitDefault(Animal animal); 
}

class Animal {

    public void accept(AnimalVisitor visitor) {
        visitor.visitDefault(this);
    }
}

class Fish extends Animal {

    @Override
    public void accept(AnimalVisitor visitor) {
        visitor.visitFish(this);
    }
}

class Lion extends Animal {

    @Override
    public void accept(AnimalVisitor visitor) {
        visitor.visitLion(this);
    }
}

Then you can easily replace your loop with something like this:

然后你可以用这样的东西轻松替换你的循环:

AnimalVisitor visitor = new AnimalVisitor() {

    @Override
    public void visitLion(Lion lion) {
        // Do something with lion
    }

    @Override
    public void visitFish(Fish fish) {
        // Do something with fish
    }
}

for (Animal animal : animals) {
    animal.accept(visitor);
}

We can even take this one step further:

我们甚至可以更进一步:

Reflective visitors

Since it is annoying to add for every different kind of animal an specific visitAnimal method, we can make use of reflection to avoid this! This will result in smaller and cleaner code:

由于为每种不同种类的动物添加特定的visitAnimal方法很烦人,我们可以利用反射来避免这种情况!这将导致更小更清晰的代码:

interface Visitable { }

class Animal implements Visitable {

    // No accept method
}

class Fish extends Animal {}
class Goldfish extends Fish {}
class Shark extends Fish {}


// Take for example this visitor:

class BittenByVisitor extends ReflectiveVisitor {


    private Surfer surfer;

    public BitByVisitor(surfer) {
        this.surfer = surfer;
    }

    // We only care about the sharks:

    public void visit(Shark shark) {

        surfer.die();
    }


    // Any other fish is just the same:

    public void visit(Fish fish) {

        surface.decreaseHealthBy(1);
    }

    // It also works with interfaces:
    public void visit(VerySmallFish fish) {

        // Do nothing by purpose!
    }
}

And here an implementation of the reflective visitor:

这里是反思访客的实现:

abstract class ReflectiveVisitor {

    public void visit(Visitable v) throws NoSuchMethodException {
        Method m = findMethod(v);

        try {
            m.invoke(this, new Object[] { v });
        }

        catch ( IllegalAccessException e1 ) { /* code handling */ }
        catch ( InvocationTargetException e2 ) { /* code handling */ }
    }

    private Method findMethod(Visitable v) throws NoSuchMethodException {

        String methodName = "visit";
        Class visitable = v.getClass();

        while ( isAncestorOf("Visitable", visitable) {

            Class visitor = getClass();

            while ( isAncestorOf("Visitor", visitor) {

                try {
                    Method m = visitor.getDeclaredMethod(methodName, new Class[]{visitable});
                    return m;
                } catch ( NoSuchMethodException e ) {
                    visitor = visitor.getSuperclass();
                }
            }

            visitable = visitable.getSuperclass();
        }

        String errMsg = "put error message here";
        throw new NoSuchMethodException(errMsg);
    }

    private boolean isAncestorOf(String ancestorName, Class descendant) {

        try {
            return Class.forName(ancestorName).isAssignableFrom(descendant);
        }
        catch ( ClassNotFoundException e ) { /* code handling */ }
            return false;
        }
    }
}

Source code is taken from this paper.

源代码摘自本文。

I personally like to use a reflective visitor which avoids the Visitable class. You can define it like this:

我个人喜欢使用反射访问者来避​​免Visitable类。您可以这样定义:

class ReflectiveVisitor<T> {

    public void visit(T visitable);
}