How do I get a class instance of generic type T?
The short answer is, that there is no way to find out the runtime type of generic type parameters in Java. I suggest reading the chapter about type erasure in the Java Tutorial for more details.
A popular solution to this is to pass the Class
of the type parameter into the constructor of the generic type, e.g.
class Foo<T> {
final Class<T> typeParameterClass;
public Foo(Class<T> typeParameterClass) {
this.typeParameterClass = typeParameterClass;
}
public void bar() {
// you can access the typeParameterClass here and do whatever you like
}
}
Get Class-object representation of generic parameter in Java
The reason why
Class<T> persistentClass = (Class<T>)
((ParameterizedType)getClass().getGenericSuperclass())
.getActualTypeArguments()[0];
works was because the superclass of this
happens to be a class with a parameterised type as its superclass. Therefore you can get the actual type arguments of that type. The type parameters of superclasses are stored as metadata in the class file if you write them in the source file.
However, in your case, whatever is passed to the onCatch
parameter is not going to have a superclass of Consumer<T>
. After all, Consumer<T>
is not a class! You need to use getGenericInterfaces
and find the one that has the name that starts with java.util.function.Consumer
.
System.out.println(
// I've assumed the Consumer interface is the first one, to keep it brief
((ParameterizedType)onCatch.getClass().getGenericInterfaces()[0])
.getActualTypeArguments()[0]
);
This would work if the caller calls onCatch
like this:
onCatch(new Consumer<RuntimeException>() {
@Override
public void accept(RuntimeException e) {
}
});
The anonymous class will implement Consumer<RuntimeException>
, and this information will be written to the class file representing the anonymous class.
However, if you use a lambda:
onCatch((RuntimeException e) -> {});
Then only a method like this is generated in the same class as the caller:
private static void lambda$caller$0(RuntimeException e) {
}
and at runtime, invokedynamic
is used to create an instance that implements Consumer
, and this is the bad news: the type parameter RuntimeException
is not part of the generated class for this instance, for whatever reason.
The only way you can find RuntimeException
now then, is if you somehow know who the caller is, and find the lambda$caller$0
method, and look at its parameter.
That said, everything I've wrote so far is pretty much all implementation detail, and I wouldn't use any of that in production code. I would say you should just add a Class<E>
parameter:
onCatch(RuntimeException.class, e -> {});
It doesn't look that different on the caller's side anyway.
Instantiate a generic class T object and return it
Generic types are a compile-time notation for ensuring type safety. They are erased at runtime.
This means T
and U
do not exist at runtime. Which is why you can’t instantiate them.
You can, however, pass in the constructors yourself:
public class Button<T, U> {
private final Supplier<? extends T> tConstructor;
private final Supplier<? extends U> uConstructor;
public Button(Supplier<? extends T> tConstructor,
Supplier<? extends U> uConstructor) {
this.tConstructor = tConstructor;
this.uConstructor = uConstructor;
}
public T observe() {
return tConstructor.get();
}
public U click() {
return uConstructor.get();
}
}
And you can pass those constructors as method references:
public class FirstPage {
public Button<FirstPage, SecondPage> buttonOnFirstPage =
new Button<>(FirstPage::new, SecondPage::new);
}
Specifying a generic type in java from Class object
<T extends Number> ArrayList<T> createAList(Class<T> type)
{
ArrayList<T> toReturn = new ArrayList<>();
return toReturn;
}
ArrayList<Integer> intList = createAList(Integer.class);
Java: Get ClassT object of generic class
As mentioned by Pshemo in a comment you can't really do this in Java directly because of type erasure. However, a couple of ways to achieve that would be to take the class as a parameter of the someFunction
. E.g.
public class MyObject<T extends SomeClass1, S extends SomeClass2> {
// ....
public void someFunction(Class<T> clazz) {
ExternalClass.doSomething(clazz); // problem here!
}
}
Then you would push the problem further out.
In case you have a field of type T
that has an object of that type you could use that to pass to the ExternalClass
, e.g.
public class MyObject<T extends SomeClass1, S extends SomeClass2> {
private T t;
public MyObject(T t) {
this.t = t;
}
public void someFunction() {
ExternalClass.doSomething(t.getClass()); // problem here!
}
}
A third option if you can not alter the signature of neither the constructor nor the someFunction
would be to maldate a call to a setter method that you control, e.g.
public class MyObject<T extends SomeClass1, S extends SomeClass2> {
private T t;
public void someFunction() {
ExternalClass.doSomething(t.getClass()); // problem here!
}
public void setClazz(T t) {
this.t = t;
}
}
You could expand on this and let the caller register a callback that you use to resolve the class, but that might be overkill...
Related Topics
How to Select an Item from a Dropdown List Using Selenium Webdriver with Java
Jframe.Dispose() VS System.Exit()
How to Use Collections.Sort() in Java
How to Change the Color of Titlebar in Jframe
Method Calls Inside a Java Class Return an "Identifier Expected After This Token" Error
Abnormal Behaviour of the Zoom in and Zoom Out Functionality of the Jfreechart
Java Hashmap Performance Optimization/Alternative
Jdbc Driver Throws "Resultset Closed" Exception on Empty Resultset
Get Integer Value of the Current Year in Java
What Is the Best Open-Source Java Charting Library? (Other Than Jfreechart)
How to Use Classloader.Getresources() Correctly
Javax.Mail.Authenticationfailedexception Is Thrown While Sending Email in Java