Instantiating Object of Type Parameter

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



Leave a reply



Submit