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

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

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

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


person Mercurious    schedule 18.11.2008    source источник


Ответы (6)


После стирания типа все, что известно о 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();
  }

}
person erickson    schedule 18.11.2008
comment
В каком пакете находится Supplier? ` MyClass(Class‹? extends T› impl)` должен объявить ` throws NoSuchMethodException` для компиляции. К сожалению, ваш ответ не подходит для новичков в Java. - person purucat; 12.09.2016
comment
@user927387 java.util.function.Supplier - person erickson; 12.09.2016
comment
Поставщик‹T› требует Java 8, JFTR везде, где это необходимо. - person Fran Marzoa; 12.03.2018

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

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

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

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

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

person Community    schedule 19.11.2008

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

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

class MyClass<T> 
{
    T field;
    public void myMethod(MyFactory<T> factory)
    {
       field = factory.newObject()
    }
}
person Dan Hodge    schedule 18.11.2008
comment
Хороший, нерефлексивный подход; отражение не всегда вариант. myMethod должен иметь возможность принимать MyFactory‹? расширяет T›, верно? - person erickson; 19.11.2008
comment
Хороший вызов - вы захотите поместить ограниченный подстановочный знак в фабрику, чтобы разрешить создание объектов типа T и подклассов T в myMethod(). - person Dan Hodge; 20.11.2008

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

person krosenvold    schedule 18.11.2008

Одним из вариантов было бы бросить его с помощью Object

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

Первоначально поле будет иметь тип Object, но затем оно будет приведено к типу T. Это некрасиво, потому что уменьшение приведения к нулю — это то, что должно быть целью для инициализации объекта. Но я думаю, что это сработает.

person Zakir    schedule 17.12.2020

Класс classOfT

        try {
            t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
        } catch (Exception e) {
            e.printStackTrace();
        }
person Kevendra    schedule 18.11.2017
comment
Где объявлен этот класс classOfT? - person Fran Marzoa; 12.03.2018