Instantiating Generics Type in Java

Instantiating generics type in java

public class Abc<T> {
public T getInstanceOfT(Class<T> aClass) {
return aClass.newInstance();
}
}

You'll have to add exception handling.

You have to pass the actual type at runtime, since it is not part of the byte code after compilation, so there is no way to know it without explicitly providing it.

Instantiating a generic class in Java

One option is to pass in Bar.class (or whatever type you're interested in - any way of specifying the appropriate Class<T> reference) and keep that value as a field:

public class Test {
public static void main(String[] args) throws IllegalAccessException,
InstantiationException {
Generic<Bar> x = new Generic<>(Bar.class);
Bar y = x.buildOne();
}
}

public class Generic<T> {
private Class<T> clazz;

public Generic(Class<T> clazz) {
this.clazz = clazz;
}

public T buildOne() throws InstantiationException, IllegalAccessException {
return clazz.newInstance();
}
}

public class Bar {
public Bar() {
System.out.println("Constructing");
}
}

Another option is to have a "factory" interface, and you pass a factory to the constructor of the generic class. That's more flexible, and you don't need to worry about the reflection exceptions.

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);

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 can I instantiate a generic type in Java?

Due to type erasure, you can't instantiate generic objects. Normally you could keep a reference to the Class object representing that type and use it to call newInstance(). However, this only works for the default constructor. Since you want to use a constructor with parameters, you'll need to look up the Constructor object and use it for the instantiation:

protected <T> T getProperty(String key, T fallback, Class<T> clazz) {
String value = properties.getProperty(key);

if (value == null) {
return fallback;
} else {

//try getting Constructor
Constructor<T> constructor;
try {
constructor = clazz.getConstructor(new Class<?>[] { String.class });
}
catch (NoSuchMethodException nsme) {
//handle constructor not being found
}

//try instantiating and returning
try {
return constructor.newInstance(value);
}
catch (InstantiationException ie) {
//handle InstantiationException
}
catch (IllegalAccessException iae) {
//handle IllegalAccessException
}
catch (InvocationTargetException ite) {
//handle InvocationTargetException
}
}
}

However, seeing how much trouble it is to achieve this, including the performance cost of using reflection, it's worth looking into other approaches first.

If you absolutely need to take this route, and if T is limited to a distinct set of types known at compile time, a compromise would be to keep a static Map of Constructors, which is loaded at startup - that way you don't have to dynamically look them up at every call to this method. For example a Map<String, Constructor<?>> or Map<Class<?>, Constructor<?>>, which is populated using a static block.

Cannot instantiate generic data type in class

In java language generics are implemented by erasure, so it is impossible to instantiate a generic type. Also it is impossible to instiate an array of generic type and so on.

How can I overcome this ? I want to add a new copy of the argument
that is being passed to addData into my list.

You can try to use Cloneable interface as a type bound or add your own similar interface.

can I reflectively instantiate a generic type in java?

The generic information is lost in runtime. There is no runtime equivalent of a Creator<String>.class. You could create a type between Creator and StringCreator which fixes the generic type:

public interface Creator<T> {
T create();
}
public interface StringCreator extends Creator<String> { }
public class StringCreatorImpl implements StringCreator {
public String create() { return new String(); }
}
public class FancyStringCreator implements StringCreator {
public String create() { return new StringBuffer().toString(); }
}
public static void main(String[] args) throws Exception {
Class<?> someClass = Class.forName(args[0]);
Class<? extends StringCreator> creatorClass = someClass.asSubclass(StringCreator.class);
Constructor<? extends StringCreator> creatorCtor = creatorClass.getConstructor((Class<?>[]) null);
Creator<String> creator = creatorCtor.newInstance((Object[]) null);
}

But of course you lose a bit of flexibility, because you cannot use the following creator class:

public class AnotherCreator implements Creator<String> {
public String create() { return ""; }
}

Java Generic Class Instantiation without Type Argument

Here, as Jon Skeet said, you are using a raw type in your variable declaration.

 Generic gen=new Generic(1,2);
int a=gen.get_a();

it does not work and gives

required:int Found:Java.Lang.Object

The compiler cannot guess the type if you don't specify it when you declare the variable.

So does the erasure replace T with Object type since T cannot be
primitive, when no type argument is passed?

Using types demands specifying class in the declaration. And a primitive is not a class.
Generic<int> gen = new Generic<>(1); will not compile

So, you have to specify the wrapper object of int primitive if you want to type your instance with an integer value :
Generic<Integer> gen = new Generic<>(1);
You must have done noticed it when you declare a collection variable with generics relying on numeric types.

Object is the root class in Java and as in your caseT doesn't extend any explicit class, T derives from Object implicitly.

So, it you use a raw type in your variable, you manipulate objects.

I suppose that the compiler considers that the returned type of unspecified T is the most specific and compatible type for T and in your case it is Object.

You have the same behavior with a collection : at compile-time, a raw java.util.List manipulates Object when T is encountered.


Edit :
Here, I will give you another example to illustrate that with raw types, instead of declare type, the Object class is not necessarily used by the compiler if the type declared in the class extends another class. Contrary to what you may think.

If the Generic class was declared like that :

public class Generic<T extends MyClass>{
...
}

Even by using a raw type in the declaration of the variable, get_a() would return a MyClass object since the most specific and compatible type for T is not Object but MyClass.

 Generic gen = new Generic(1);
MyClass myClass = gen.get_a(new MyClass());

Instantiate a Generic Type

You could do

public class MyClass<T extends MyComponent> {
private T t;

MyClass(Class<T> clazz) throws InstantiationException,
IllegalAccessException {
t = clazz.newInstance();
}

}


Related Topics



Leave a reply



Submit