Instantiating object of type parameter
After type erasure, all that is known about T
is that it is some subclass of Object
. You need to specify some factory to create instances of T
.
One approach could use a Supplier<T>
:
class MyClass<T> {
private final Supplier<? extends T> ctor;
private T field;
MyClass(Supplier<? extends T> ctor) {
this.ctor = Objects.requireNonNull(ctor);
}
public void myMethod() {
field = ctor.get();
}
}
Usage might look like this:
MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);
Alternatively, you can provide a Class<T>
object, and then use reflection.
class MyClass<T> {
private final Constructor<? extends T> ctor;
private T field;
MyClass(Class<? extends T> impl) throws NoSuchMethodException {
this.ctor = impl.getConstructor();
}
public void myMethod() throws Exception {
field = ctor.newInstance();
}
}
Instantiate an object of a class where the class is given via generics
You can't do this nicely due to type erasure. The standard means of doing it is to pass the appropriate Class
object, and use this to instantiate a new instance.
e.g. from here:
public static <E> void append(List<E> list, Class<E> cls) throws Exception {
E elem = cls.newInstance(); // OK
list.add(elem);
}
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);
}
Instantiating an object of a type parameter using reflections
class Pair<T>
{
T var;
<T> Pair(){}
<T> Pair(Class<T> reflection){
var = reflection.newInstance() ;
}
<T> void func(){
System.out.println(var);
}
}
The <T>
s on the constructors and method are defining another type variable which hides the one on the class. They are all called "T
", but they're different types.
(The ones on the zero-arg constructor and func
are unused anyway).
Remove these extra type variable declarations.
class Pair<T> {
T var;
Pair() {}
Pair(Class<T> reflection) {
var = reflection.newInstance();
}
void func() {
System.out.println(var);
}
}
Then you just have to deal with the fact that not all classes have accessible zero-arg constructors; and that newInstance()
throws checked exceptions that you would need to handle.
A better approach would be to provide a Supplier<T>
:
Pair(Supplier<T> reflection) {
var = reflection.get();
}
Java Instantiate Generic Type
Java pattern to deal with this is to store Class<E>
, and use its newInstance
method, as follows:
// Class<E> object will be used to create new instances
private final Class<E> stateClass;
// Users will pass the class to StateMachine's constructor
public StateMachine(Entity entity, Class<E> stateClass) {
this.entity = entity;
this.stateClass = stateClass;
states = new ArrayMap<S, E>();
}
Now you can create new state objects as follows:
E state = stateClass.newInstance(); // Only parameterless constructors are supported
state.setEntity(entity);
Why is it possible to instantiate a generic class without having specified the generic type parameter
A reasonable option which is recommended in other similar threads is to default to the never
type. This will undoubtedly cause an issue further down the line as the never
type can't be used for anything meaningful, so callers of your class will realize they have done something wrong and that they need to pass a type argument to Foo.
type valueType<T> = {
name: string,
key: T|null,
};
class Foo<T = never> {
private value: valueType<T>;
public constructor() {
this.value = {
name: '',
key: null,
};
}
public setValue(value: valueType<T>) {
this.value = value;
}
public getValue(): valueType<T> {
return this.value;
}
}
const foo = new Foo();
// bar will now have the `never` type, making it unusable
const bar = foo.getValue();
Related Topics
Preserving Parameter/Argument Names in Compiled Java Classes
Why Can't a Generic Type Parameter Have a Lower Bound in Java
Select an Option from the Right-Click Menu in Selenium Webdriver - Java
How to Convert String to Date Without Knowing the Format
How to Read the Manifest File for a Webapp Running in Apache Tomcat
Eclipse Error: "Failed to Connect to Remote Vm"
Declaring and Initializing Variables Within Java Switches
The Server Time Zone Value 'Aest' Is Unrecognized or Represents More Than One Time Zone
How to Convert a Byte Array into a Double and Back
Invalid Thread Access Error with Java Swt
Variable's Scope in a Switch Case
Error: Javafx Runtime Components Are Missing, and Are Required to Run This Application with Jdk 11
The Resourceconfig Instance Does Not Contain Any Root Resource Classes
Differencebetween the Float and Integer Data Type When the Size Is the Same