How to compare types in Java

Here’s an overview of the different methods to identify a type or Object in Java.

There are three basic cases

  1. I want to detect if two variables point to Objects of the same type
  2. I want to detect if two types are compatible
  3. I want to detect if a given variable points to an Object of a given type

Check if two variables point to Objects of the same type

The first way is both the most useless and the most cumbersome, so lets’s get it over with fast:

boolean sameType = ob1.getClass() == obj2.getClass();

That was easy enough, but it gets messy as soon as one of the two may be null:

boolean sameType = (obj1 == obj2 || 
                     (obj1 != null
                      && obj2 != null
                      && obj1.getClass() == obj2.getClass())

Check if two types are compatible

In the following, I will be using the word type as a synonym for Class objects, which can actually be classes, interfaces, enums and annotations. In this section I’ll ignore null. If you can’t even get your types null-safe, you’re screwed anyway.

If you need two types to be identical, just compare them for identity. According to the Java Language Specification, reference types with equal declarations are actually the same Object

boolean sameType = type1 == type2;

If you need type1 to be a subtype of type2 (where subtype means any kind of extends or implements relation

boolean sameType = type2.isAssignableFrom(type1);
// Examples:
assert List.class.isAssignableFrom(ArrayList.class); // Class ArrayList implements Interface List
assert Collection.class.isAssignableFrom(List.class); // Interface List extends Interface Collection
assert AbstractList.class.isAssignableFrom(ArrayList.class); // Class ArrayList extends
                                                             // Class AbstractList

Check if a variable is of a given type

That’s easiest if you know the type at Compile time

boolean typeOrSubType = obj instanceof SomeType

There are two nice side effects of this check:

  1. it includes an implicit null check, there’s no need to separately check for null
  2. it generates a compile-time error if the types are not related:
String obj = // some code that may or may not initialize the String
boolean typeOrSubType = obj instanceof Integer // this generates a compile error, as the compiler
                                               // knows this can never be true

If you only know the type at runtime, the compiler can’t help you with static analysis, but you’re not completely lost.

Class<?> type = // get the type from somewhere. again, we'll assume the type is not null
boolean typeOrSubType = type.isInstance(obj);

Again, Class.isInstance(Object) gives you an implicit null check.

The above methods check whether the object is an instance of the type or a subtype. If you need to check for the exact type (without subtypes), you can use this code

boolean isExactType = obj != null && obj.getClass() == type;

The distinction between a) exact type and b) type or subtype is mostly important when it comes to overriding the equals(Object) method, depending on your interpretation of the equals() contract. This is discussed in Effective Java Item 8: Obey the general contract when overriding equals and has been discussed various times on StackOverflow, most broadly in the thread Overriding equals and hashCode in Java.

Special types

There are some special methods for some special types of types (pun intended).

Here’s how to detect enums:

enum Duck{
assert Duck.class.isEnum(); // detect that a type is an enum
assert Enum.class.isAssignableFrom(Duck.class); // equivalent, but more cumbersome
Object obj = Duck.HUEY; // << you usually don't want to do this, but we need it for the next line
assert obj instanceof Enum;

Here’s how to detect arrays:

assert String[].class.isArray(); // works for Object arrays,
assert int[].class.isArray();    // for primitive arrays
assert int[][].class.isArray();  // and for multidimensional arrays

Note that you can only identify arrays via their types. There’s no legal instanceof check, so for checking a variable you need to check it for null first:

boolean isArray = obj != null && obj.getClass().isArray()

There’s also the Class.getComponentType() method for detecting an Array’s type. You can use that to detect a multidimensional array:

Class<?> componentType = type.getComponentType();
boolean isMultiDimensionalArray = componentType != null && componentType.isArray();

As you can see, this is rather ugly. Actually, code related to arrays is almost always ugly in Java, which is one of the reasons most people prefer to use Collections over arrays.

Here’s how to detect primitive types:

assert int.class.isPrimitive();

Note that there is no legal way to check the type of a primitive variable, as the type of primitive variables is always known to be the variable type. While an Object can actually be a String, and int can never be a long. Both of these generate compiler errors:

assert 1 instanceof int;
assert 1 instanceof Integer;

There’s also no easy way to detect if an Object is of one of the primitive wrapper types. If you have access to the Guava library, you can use Primitives.isWrapperType(Class) for this, though.

This entry was posted in Uncategorized and tagged , , . Bookmark the permalink.

2 Responses to How to compare types in Java

  1. Paul Ebermann says:

    Your first “null-safe-check” actually fails with a NullPointerException if obj1 != null and obj2 == null.

    boolean sameType = (obj1 == null ? obj2 == null : obj1.getClass() == obj2.getClass());

    So it becomes even more ugly:

    boolean sameType = (obj1 == null ? obj2 == null : obj2 != null && obj1.getClass() == obj2.getClass());

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s