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!
The java “instanceof” operator is used to test whether the object is an instance of the specified type (class or subclass or interface). It is also known as type comparison operator because it compares the instance with type. It returns either true or false.
Arrays of more derived classes are subclasses of the corresponding array classes.
Python issubclass() is built-in function used to check if a class is a subclass of another class or not. This function returns True if the given class is the subclass of given class else it returns False. Parameters: Object: class to be checked.
If this Class object represents a primitive type, this method returns true if the specified Class parameter is exactly this Class object; otherwise it returns false . Reference: Class. isAssignableFrom(Class)
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.
}
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.
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:
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);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With