Создание экземпляра объекта типа parameter


У меня есть шаблон класса следующим образом:

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

Как создать новый экземпляр T в моем классе?

5 66

5 ответов:

после стирания типа, все, что известно о T Это какой-то подкласс Object. Вам нужно указать некоторую фабрику для создания экземпляров T.

можно использовать 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();
  }

}

использование может выглядеть так:

MyClass<StringBuilder> it = new MyClass<>(StringBuilder::new);

кроме того, вы можете предоставить Class<T> объект, а затем использовать отражение.

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

}

другой нерефлексивный подход заключается в использовании гибридного конструктора / абстрактного Заводского шаблона.

в эффективной Java Джошуа блох подробно рассматривает шаблон Builder и защищает общий интерфейс Builder:

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

конкретные строители могут реализовать этот интерфейс, а внешние классы могут использовать конкретный Строитель для настройки строителя по мере необходимости. Построитель может быть передан в MyClass как Builder<T>.

используя этот шаблон, вы можете сделать новые экземпляры T, даже если T параметры конструктора или требует дополнительной настройки. Конечно, вам понадобится какой-то способ передать строителя в MyClass. Если вы не можете передать что-либо в MyClass, то Builder и Abstract Factory отсутствуют.

Это может быть более тяжелым, чем то, что вы ищете, но это также будет работать. Обратите внимание, что если вы используете этот подход, было бы более разумно вводить фабрику в MyClass при ее создании вместо того, чтобы передавать ее в ваш метод каждый раз, когда он вызывается.

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

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

Если вы готовы к подклассу, вы также можете избежать стирания, проверьте http://www.artima.com/weblogs/viewpost.jsp?thread=208860

класс classOfT

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