101

Is there a way to determine if an object is an instance of a generic type?

public <T> test(Object obj) {
    if (obj instanceof T) {
        ...
    }
}

That clearly doesn't work. Is there an alternative? Like I want to use Java reflection to instantiate a class and then check to make sure it is of type generic T.

Lii
  • 11,553
  • 8
  • 64
  • 88
Nikordaris
  • 2,297
  • 5
  • 20
  • 30

6 Answers6

150

The only way you can do this check is if you have the Class object representing the type:

Class<T> type; //maybe passed into the method
if ( type.isInstance(obj) ) {
   //...
}
Mark Peters
  • 80,126
  • 17
  • 159
  • 190
27

To extend the sample of Mark Peters, often you want to do something like:

Class<T> type; //maybe passed to the method
if ( type.isInstance(obj) ) {
   T t = type.cast(obj);
   // ...
}
Puce
  • 37,247
  • 13
  • 80
  • 152
15

If you don't want to pass Class type as a parameter as mentioned by Mark Peters, you can use the following code. Kudos to David O'Meara.

  Class<T> type = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass())
                  .getActualTypeArguments()[0];
  if (type.isInstance(obj)) {
      ...
  }
Ton Snoei
  • 2,637
  • 22
  • 23
5

You could try this,

// Cast your object to the generic type.
T data = null;
try {
    data = (T) obj;
} catch (ClassCastException cce) {
    // Log the error.
}

// Check if the cast completed successfully.
if(data != null) {
    // whatever....
}
Georgios Syngouroglou
  • 18,813
  • 9
  • 90
  • 92
  • 7
    **This does not work!** The cast succeeds for **all** types. Which is why it gives an "Unchecked cast" compile warning. – Lii Feb 02 '18 at 08:47
3

It would make more sense to put the restriction on where the type T is used to parametrise the Class type. When you pass the type in, instead of using something like Class<?>, you should use Class<? extends T>.

Chris Dennett
  • 22,412
  • 8
  • 58
  • 84
  • 1
    If you want to know the exact type of T at runtime, it is important to require that the caller pass in a Class, not a Class extends T>. For example, Puce's code would not compile with Class extends T>. – Theodore Murdock May 21 '14 at 20:38
1

This will only work (partly) if you have an object of type T. Then you can get the class of that object, see java.lang.Class<T> and find if it's the same as the object in question.

But note that this goes counter the very reason we have genrics: using a generic type is a way to say that you don't care what type it really is (up to upper and lower bounds that may be specified).

Ingo
  • 36,037
  • 5
  • 53
  • 100
  • The Class> returned from a .getClass() call on a non-null T instance is not guaranteed to be a Class. The best you can guarantee is that it's a Class extends T>. – Theodore Murdock May 21 '14 at 20:43