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…

 
---

Comment

 
---