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
}
}
What's the equivalent of T.class in a generic class?
This is a limitation of generics in Java. The generics only exist at compile time, i.e. at runtime the object is just a BaseConverter
, and so you can't query it about its generic type. The easiest solution is usually to pass in a Class<TModel>
object (as you are doing) when you call the method. You can also pass it to the constructor for BaseConverter
if you don't want to have to pass it in multiple times.
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);
}
How to create an instance just by generic type T
The generic information will be erased at compile time, so there will be no T
anymore during runtime (you loose the information). Thats why you somewhere will need a Class<>
to store the information.
The most clean & simple solution form my point of view is to pass in the class to to the constructor. I know you requested it to be without any constructor argument, but I do not think this is possible.
Code Sample
public abstract class AbstractBase<T> {
private final T genericTypeObject;
protected Base(Class<T> type){
try {
genericTypeObject = type.newInstance();
} catch (InstantiationException e) {
// Handle
} catch (IllegalAccessException e) {
// Handle
}
}
}
public class Child extends Base<SomeClass> {
public Child () {
super(SomeClass.class);
}
}
Alternative Solution
Using a Supplier
(thanks for the comment @Jorn Vernee):
public abstract class AbstractBase<T> {
private final T genericTypeObject;
public AbstractBase(Supplier<T> supplier) {
genericTypeObject = supplier.get();
}
}
public class Child extends AbstractBase<SomeClass> {
public Child() {
super(SomeClass::new);
}
}
Create instance of generic class parameter
In short: No it's not possible without a reference to a constructible runtime value.
The reason is that TypeScript types only exist at compile time (not at runtime) and can't be used as values. In your example, T
is only a type (not a runtime value). This is the JavaScript that your TypeScript program compilation would produce:
class Bar {}
class Foo {
constructor() { }
create() {
return new T();
}
}
const bar = new Foo().create();
// ^^^^^^^^
// Exception is thrown: ReferenceError: T is not defined
Java generics - get class?
Short answer: You can't.
Long answer:
Due to the way generics is implemented in Java, the generic type T is not kept at runtime. Still, you can use a private data member:
public class Foo<T>
{
private Class<T> type;
public Foo(Class<T> type) { this.type = type; }
}
Usage example:
Foo<Integer> test = new Foo<Integer>(Integer.class);
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.
Related Topics
Showing Firebase Data in Listview
Working Post Multipart Request With Volley and Without Httpentity
What's the Difference Between JavaScript and Java
How to Compare Strings in Java
What Causes a Java.Lang.Arrayindexoutofboundsexception and How to Prevent It
How to Set Java_Home in Linux For All Users
Downloading Java Jdk on Linux Via Wget Is Shown License Page Instead
Base 64 Encode and Decode Example Code
Android/Java - Date Difference in Days
Why Do I Get "Failed to Bounce to Type" When I Turn Json from Firebase into Java Objects
Android: Internet Connectivity Change Listener
Cannot Create or Edit Android Virtual Devices (Avd) from Eclipse, Adt 22.6
Java String to Date Conversion
How to Use Java.Net.Urlconnection to Fire and Handle Http Requests
Problems Submitting a Login Form With Jsoup
How to Access the Java Method in a C++ Application