6

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

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!

Linuxn00b
  • 151
  • 2
  • 12
  • Do you just want the names of the particular class? You can print the name. If you have a set number to test, you can use `instanceof`. What are you attempting to accomplish? โ€“ KevinO Apr 02 '16 at 20:22
  • 2
    There is instanceof, of course, but using instanceof is a design smell. You should instead use polymorphism. Call a method on Animal, and the subclass method will be called and do what is appropriate for that kind of animal. โ€“ JB Nizet Apr 02 '16 at 20:24
  • 1
    Could explain what exactly it is you are trying to do? โ€“ Boris the Spider Apr 02 '16 at 20:27

3 Answers3

7

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.

for (Animal a : myAnimals) {
    if (a instanceof Lion) System.out.println("Lion");
    // etc.
}
Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
2

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

 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.


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:

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:

class ReflectiveVisitor<T> {

    public void visit(T visitable);
}
Community
  • 1
  • 1
Tim
  • 5,521
  • 8
  • 36
  • 69
1

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