instanceof
instanceof is a binary operator that checks if an instance is of a certain type. You use it this way:
String tmp = "hello";
if (tmp instanceof String) {
// ... do things
}
On the left-hand side, you have the instance, and on the right-hand side, you have the type. As all classes are descendants of Object
, all instances except for null
, return true when instanceof
’ed with Object
.
Here are the most obvious usages in this test case:
import static org.junit.Assert.*; import org.junit.Test;
public class TestInstance { interface Interface {
}
class InterfaceImpl implements Interface {
}
class SubInterfaceImpl extends InterfaceImpl {
}
enum AnEnum { ENUM_ELT }
@Test public void testInstanceOf() { assertFalse(null instanceof Object);
// The following statements do not compile // assertTrue(null instanceof null); // assertTrue(1 instanceof int); // assertTrue(1 instanceof Integer);
assertTrue("Hello" instanceof String);
assertTrue(new InterfaceImpl() instanceof Object);
assertTrue(new InterfaceImpl() instanceof Interface); assertTrue(new InterfaceImpl() instanceof InterfaceImpl);
assertTrue(new SubInterfaceImpl() instanceof Interface); assertTrue(new SubInterfaceImpl() instanceof InterfaceImpl); assertTrue(new SubInterfaceImpl() instanceof SubInterfaceImpl);
assertTrue(new InterfaceImpl[5] instanceof InterfaceImpl[]); assertTrue(new InterfaceImpl[5] instanceof Interface[]);
assertTrue(new java.util.ArrayList<Interface>() instanceof java.util.ArrayList); assertTrue(new java.util.ArrayList<Interface>() instanceof java.util.List); assertTrue(new java.util.ArrayList<Interface>() instanceof java.util.Collection);
// but the following statements do not compile: // assertTrue(new java.util.ArrayList<Interface>() instanceof java.util.ArrayList<Object>); // assertTrue(new java.util.ArrayList<Interface>() instanceof java.util.ArrayList<Interface>); // whilst these do:
assertTrue(new java.util.ArrayList<Interface>() instanceof java.util.ArrayList<?>); assertTrue(new java.util.ArrayList<Interface>() instanceof java.util.List<?>); assertTrue(new java.util.ArrayList<Interface>() instanceof java.util.Collection<?>);
assertTrue(AnEnum.ENUM_ELT instanceof AnEnum); } }
Generally speaking, instanceof
is to be avoided as checking the type of an object before performing tasks with it is a code smell, and a sign that something is wrong in the design and should be refactored. Typically used with a cast right after:
public class Monster { // ... }
public class BeheadedGiantPangolin extends Monster { public void yellAndPokeOpponentEyes(Monster m) { // ... } // ... }
public class KillerBloodThirstyBunny extends Monster { public void drinkBlood(Monster m) { // ... } // ... }
// ... if (monster instanceof BeheadedGiantPangolin) { BeheadedGiantPangolin pangolin = (BeheadedGiantPangolin)monster; pangolin.yellAndPokeOpponentEyes(otherMonster); } else if (monster instanceof KillerBloodThirstyBunny) { KillerBloodThirstyBunny bunny = (KillerBloodThirstyBunny)monster; bunny.drinkBlood(otherMonster); }
Here the obvious problem is that polymorphism should be used:
public class Monster {
public void attack(Monster m) {
}
public static void main(String[] args) { Monster monster = new BeheadedGiantPangolin(); Monster otherMonster = new KillerBloodThirstyBunny();
monster.attack(otherMonster); } // ... }
public class BeheadedGiantPangolin extends Monster { public void attack(Monster m) { yellAndPokeOpponentEyes(m); }
public void yellAndPokeOpponentEyes(Monster m) { // ... } }
public class KillerBloodThirstyBunny extends Monster { public void attack(Monster m) { drinkBlood(m); }
public void drinkBlood(Monster m) { // ... } }
However, in some situations, you do have to use instanceof
, or check the type of an object. And this is the purpose of this post.
The most notable “problem” about instanceof
is that it is not dynamic: you cannot put the type into a variable to do something like:
Type type = KillerBloodThirstyBunny;
// ...
if (monster instanceof type) {
// ...
There is however another way.
Class.isInstance
Class.isInstance [1] is the “dynamic equivalent” of instanceof. And we can verify this quite easily:
import static org.junit.Assert.*;
import org.junit.Test;
public class TestIsInstance { interface Interface {
}
class InterfaceImpl implements Interface {
}
class SubInterfaceImpl extends InterfaceImpl {
}
enum AnEnum { ENUM_ELT }
@Test public void testInstanceOf() { assertFalse(Object.class.isInstance(null));
assertTrue(Integer.class.isInstance(1)); assertTrue(String.class.isInstance("Hello"));
assertTrue(Object.class.isInstance(new InterfaceImpl()));
assertTrue(Interface.class.isInstance(new InterfaceImpl())); assertTrue(InterfaceImpl.class.isInstance(new InterfaceImpl()));
assertTrue(Interface.class.isInstance(new SubInterfaceImpl())); assertTrue(InterfaceImpl.class.isInstance(new SubInterfaceImpl())); assertTrue(SubInterfaceImpl.class.isInstance(new SubInterfaceImpl()));
assertTrue(InterfaceImpl[].class.isInstance(new InterfaceImpl[5])); assertTrue(Interface[].class.isInstance(new InterfaceImpl[5]));
assertTrue(java.util.ArrayList.class.isInstance(new java.util.ArrayList<Interface>())); assertTrue(java.util.List.class.isInstance(new java.util.ArrayList<Interface>())); assertTrue(java.util.Collection.class.isInstance(new java.util.ArrayList<Interface>()));
assertTrue(AnEnum.class.isInstance(AnEnum.ENUM_ELT)); } }
We even get to test whether 1 is an instance of Integer. However, this is not valid:
assertTrue(java.util.ArrayList<?>.class.isInstance(new java.util.ArrayList<Interface>()));
So now, it is possible to dynamically assign the class to a variable to test the instance:
Class aClass = BeheadedGiantPangolin.class;
if (aClass.isInstance(monster)) {
// ...
1 This reminds to broadcast the message: for the love of God, please link to the javadoc for java 6 onwards!! Fed up of getting 1.4 results when googling a class…