Instantiating object of type parameter

JavaGenericsReflection

Java Problem Overview


I have got a template class as follows:

class MyClass<T>
{
    T field;
    public void myMethod()
    {
       field = new T(); // gives compiler error
    }
}

How do I create a new instance of T in my class?

Java Solutions


Solution 1 - Java

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

}

Solution 2 - Java

Another non-reflective approach is to use a hybrid Builder / Abstract Factory pattern.

In Effective Java, Joshua Bloch goes over the Builder pattern in detail, and advocates a generic Builder interface:

public interface Builder<T> {
  public T build();
}

Concrete builders can implement this interface, and outside classes can use the concrete builder to configure the Builder as required. The builder can be passed to MyClass as a Builder<T>.

Using this pattern, you can get new instances of T, even if T has constructor parameters or requires additional configuration. Of course, you'll need some way to pass the Builder into MyClass. If you can't pass anything into MyClass, then Builder and Abstract Factory are out.

Solution 3 - Java

This may be more heavyweight than what you're looking for, but it will also work. Note that if you take this approach, it would make more sense to inject the factory into MyClass when it is constructed instead of passing it into your method each time it is called.

interface MyFactory<T> 
{
    T newObject();
}

class MyClass<T> 
{
    T field;
    public void myMethod(MyFactory<T> factory)
    {
       field = factory.newObject()
    }
}

Solution 4 - Java

If you're willing to subclass you can avoid erasure as well, check out http://www.artima.com/weblogs/viewpost.jsp?thread=208860

Solution 5 - Java

You can get the class object of type T without passing any arguments.

Try this.

static class MyClass<T> {
    Class<?> clazz;

    @SafeVarargs
    public MyClass(T... dummy) {
        if (dummy.length > 0)
            throw new IllegalArgumentException("Do not specify arguments");
        clazz = dummy.getClass().componentType();
    }

    @Override
    public String toString() {
        return "MyClass<T = " + clazz.getName() + ">";
    }
}

public static void main(String[] args) {
    MyClass<String> s = new MyClass<>();
    System.out.println(s);
    Object i = new MyClass<Integer>();
    System.out.println(i);
}

output:

MyClass<T = java.lang.String>
MyClass<T = java.lang.Integer>

You can instantiate an object of type parameter T like this.

clazz.getConstructor().newInstance();

Solution 6 - Java

One option would be to cast it with Object

{field = (T) new Object();}

field will initially be type Object, but then it will cast down to type T. This is an ugly one because reducing casting to zero is what the goal should be for object initializations. But I think this will work.

Solution 7 - Java

Class classOfT

        try {
            t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
        } catch (Exception e) {
            e.printStackTrace();
        }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionMercuriousView Question on Stackoverflow
Solution 1 - JavaericksonView Answer on Stackoverflow
Solution 2 - JavaInverseFalconView Answer on Stackoverflow
Solution 3 - JavaDan HodgeView Answer on Stackoverflow
Solution 4 - JavakrosenvoldView Answer on Stackoverflow
Solution 5 - Javauser4910279View Answer on Stackoverflow
Solution 6 - JavaZakirView Answer on Stackoverflow
Solution 7 - JavaKevendraView Answer on Stackoverflow