Instantiating object of type parameter

78,962

Solution 1

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

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

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

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

Share:
78,962

Related videos on Youtube

Mercurious
Author by

Mercurious

Updated on August 24, 2021

Comments

  • Mercurious
    Mercurious over 2 years

    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?

  • brady
    brady over 15 years
    Good, non-reflective approach; reflection isn't always an option. myMethod should be able to accept a MyFactory<? extends T>, right?
  • Dan Hodge
    Dan Hodge over 15 years
    Good call - you'll want to put a bounded wildcard on the factory to allow objects of type T and subclasses of T to be created in myMethod().
  • purucat
    purucat over 7 years
    What package the Supplier is located in? ` MyClass(Class<? extends T> impl)` must declare ` throws NoSuchMethodException` to be compiled. Your answer is unfortunately not friendly to Java beginner.
  • brady
    brady over 7 years
    @user927387 java.util.function.Supplier
  • Fran Marzoa
    Fran Marzoa about 6 years
    Supplier<T> requires Java 8, JFTR for wherever is worth.
  • Fran Marzoa
    Fran Marzoa about 6 years
    Where is that classOfT class declared?