Generics are a compile time feature. Generics add checks at compile time which may not have any meaning at runtime. This is one example. You can only check the type of the object referenced which could be a super type in code. If you want to pass the type T you have do this explicitly.
void someMethod(Class<T> tClass) {
if(String.class.isAssignableFrom(tClass))
or
void someMethod(Class<T> tClass, T tArg) {
Note: the type might not be the same,
someMethod(Number.class, 1);
Answer from Peter Lawrey on Stack OverflowGenerics are a compile time feature. Generics add checks at compile time which may not have any meaning at runtime. This is one example. You can only check the type of the object referenced which could be a super type in code. If you want to pass the type T you have do this explicitly.
void someMethod(Class<T> tClass) {
if(String.class.isAssignableFrom(tClass))
or
void someMethod(Class<T> tClass, T tArg) {
Note: the type might not be the same,
someMethod(Number.class, 1);
It won't compile because T is not a variable, but a place holder for a class that is defined at runtime. Here's a quick sample:
public class Test<T> {
public void something(T arg) {
if (arg instanceof String) {
System.out.println("Woot!");
}
}
public static void main(String[] args) {
Test<String> t = new Test<String>();
t.something("Hello");
}
}
The error message says it all. At runtime, the type is gone, there is no way to check for it.
You could catch it by making a factory for your object like this:
public static <T> MyObject<T> createMyObject(Class<T> type) {
return new MyObject<T>(type);
}
And then in the object's constructor store that type, so variable so that your method could look like this:
if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass())) {
return -1;
}
Two options for runtime type checking with generics:
Option 1 - Corrupt your constructor
Let's assume you are overriding indexOf(...), and you want to check the type just for performance, to save yourself iterating the entire collection.
Make a filthy constructor like this:
public MyCollection<T>(Class<T> t) {
this.t = t;
}
Then you can use isAssignableFrom to check the type.
public int indexOf(Object o) {
if (
o != null &&
!t.isAssignableFrom(o.getClass())
) return -1;
//...
Each time you instantiate your object you would have to repeat yourself:
new MyCollection<Apples>(Apples.class);
You might decide it isn't worth it. In the implementation of ArrayList.indexOf(...), they do not check that the type matches.
Option 2 - Let it fail
If you need to use an abstract method that requires your unknown type, then all you really want is for the compiler to stop crying about instanceof. If you have a method like this:
protected abstract void abstractMethod(T element);
You can use it like this:
public int indexOf(Object o) {
try {
abstractMethod((T) o);
} catch (ClassCastException e) {
//...
You are casting the object to T (your generic type), just to fool the compiler. Your cast does nothing at runtime, but you will still get a ClassCastException when you try to pass the wrong type of object into your abstract method.
NOTE 1: If you are doing additional unchecked casts in your abstract method, your ClassCastExceptions will get caught here. That could be good or bad, so think it through.
NOTE 2: You get a free null check when you use instanceof. Since you can't use it, you may need to check for null with your bare hands.
java - why instanceof does not work with Generic? - Stack Overflow
java - Interface generics and instanceof - Stack Overflow
java - How to get concrete type of a generic interface - Stack Overflow
How to check if a generic type implements a specific type of generic interface in java? - Stack Overflow
You cannot do it this way. Fortunately, you already have a Class<T> argument so instead do
myClass.isAssignableFrom(obj.getClass())
This will return true if obj is of class myClass or subclass.
As @ILMTitan pointed out (thanks), you will need to check for obj == null to avoid a potential NullPointerException, or use myClass.isInstance(obj) instead. Either does what you need.
Short answer: because a type parameter in Java is something just used by the compiler to grant type safety.
At runtime, type information about generic types is discarded because of type erasure but instanceof is a runtime check that needs a concrete type (not a type variable) to work.
Java doesn't care about the generic type when you use instanceof. To quote the Javadocs:
Because the Java compiler erases all type parameters in generic code, you cannot verify which parameterized type for a generic type is being used at runtime
So, you can test against Action<?> or Action, but you will get a compiler error if you try to test against Action<Integer>. The error message is very informative:
Cannot perform instanceof check against parameterized type Action<Integer>. Use the form Action<?> instead since further generic type information will be erased at runtime
I implemented it and it returns true.
Also if you leave out generics all together, like this:
if (SomeAction instanceof Action) {
. . .
}
If you try to actually include a generic type for Action in that if operation the code doesn't compile, with the message:
illegal generic type for instance of
for instance:
if (action instanceof Action<String>) {
System.out.println("is Action");
} else {
System.out.println("is not Action");
}
You can grab generic interfaces of a class by Class#getGenericInterfaces() which you then in turn check if it's a ParameterizedType and then grab the actual type arguments accordingly.
Type[] genericInterfaces = BarFoo.class.getGenericInterfaces();
for (Type genericInterface : genericInterfaces) {
if (genericInterface instanceof ParameterizedType) {
Type[] genericTypes = ((ParameterizedType) genericInterface).getActualTypeArguments();
for (Type genericType : genericTypes) {
System.out.println("Generic type: " + genericType);
}
}
}
Try something like the following:
Class<T> thisClass = null;
Type type = getClass().getGenericSuperclass();
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type[] typeArguments = parameterizedType.getActualTypeArguments();
thisClass = (Class<T>) typeArguments[0];
}
Java implements erasure, so there's no way to tell on runtime if genericObject is an instance of Set<String> or not. The only way to guarantee this is to use bounds on your generics, or check all elements in the set.
Compile-time Generic Bounds
Using bounds checking, which will be checked at compile-time:
public <T extends SomeInterface> void genericMethod(Set<? extends T> tSet) {
// Do something with tSet here
}
Java 8
We can use streams in Java 8 to do this natively in a single line:
public <T> void genericMethod(T t) {
if (t instanceof Set<?>) {
Set<?> set = (Set<?>) t;
if (set.stream().allMatch(String.class:isInstance)) {
Set<String> strs = (Set<String>) set;
// Do something with strs here
}
}
}
Java 7 and older
With Java 7 and older, we need to use iteration and type checking:
public <T> void genericMethod(T t) {
Set<String> strs = new HashSet<String>();
Set<?> tAsSet;
if (t instanceof Set<?>) {
tAsSet = (Set<?>) t;
for (Object obj : tAsSet) {
if (obj instanceof String) {
strs.add((String) obj);
}
}
// Do something with strs here
} else {
// Throw an exception or log a warning or something.
}
}
Guava
As per Mark Peters' comment below, Guava also has methods that do this for you if you can add it to your project:
public <T> void genericMethod(T t) {
if (t instanceof Set<?>) {
Set<?> set = (Set<?>) t;
if (Iterables.all(set, Predicates.instanceOf(String.class))) {
Set<String> strs = (Set<String>) set;
// Do something with strs here
}
}
}
The statement, Iterables.all(set, Predicates.instanceOf(String.class)) is essentially the same thing as set instanceof Set<String>.
You don't have that option in Java, sadly. In Java, there is no runtime difference between a List<String> and a List<Integer>. It is the compiler that ensures that you never add() an Integer to a List<String>. Even that compiler enforcement is not strict, so you can "legally" do such abominations with unchecked casts....
All in all, for (almost) any matter of runtime-type-identification, you have to take List<String> for what it actually is: just a raw List. That is called type erasure.
That said, nothing prevents you from inspecting the contents of a List for their types:
public boolean isListOf(List<?> list, Class<?> c) {
for (Object o : list) {
if (!c.isInstance(o)) return false;
}
return true;
}
To use this method:
// ...
if (genericObject instanceof List<?>) {
if (isListOf((List<?>) genericObject, String.class)) {
@SuppressWarnings("unchecked")
List<String> strings = (List<String>) genericObject;
}
}
An interesting observation: if the list is empty, the method returns true for all given types. Actually there is no runtime difference between an empty List<String> and an empty List<Integer> whatsoever.
Here's one suggestion:
public interface Service<T,U> {
T executeService(U... args);
}
public class MyService implements Service<String, Integer> {
@Override
public String executeService(Integer... args) {
// do stuff
return null;
}
}
Because of type erasure any class will only be able to implement one of these. This eliminates the redundant method at least.
It's not an unreasonable interface that you're proposing but I'm not 100% sure of what value it adds either. You might just want to use the standard Callable interface. It doesn't support arguments but that part of the interface has the least value (imho).
Here's another suggestion:
public interface Service<T> {
T execute();
}
using this simple interface you can pass arguments via constructor in the concrete service classes:
public class FooService implements Service<String> {
private final String input1;
private final int input2;
public FooService(String input1, int input2) {
this.input1 = input1;
this.input2 = input2;
}
@Override
public String execute() {
return String.format("'%s%d'", input1, input2);
}
}
Hi,
I have method signature
public void validate(Object[] params)
I need to check the type for the parameter at location 0 params[0]
to be of type Optional<String>
How ca I perform this in the context of generics?
AFAIK instanceof does not apply to such cases.
Any pointers into the right direction is highly appreicated.