Создание объекта типа параметра - PullRequest
73 голосов
/ 18 ноября 2008

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

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

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

Ответы [ 6 ]

73 голосов
/ 18 ноября 2008

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

}
13 голосов
/ 20 ноября 2008

Другим неотражающим подходом является использование гибридного шаблона Builder / Abstract Factory.

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

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

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

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

11 голосов
/ 19 ноября 2008

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

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

class MyClass<T> 
{
    T field;
    public void myMethod(MyFactory<T> factory)
    {
       field = factory.newObject()
    }
}
1 голос
/ 18 ноября 2008

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

0 голосов
/ 28 февраля 2019

Лучшее и простое решение для использования кастинга. Да, это выглядит ужасно, но лучше я видел здесь.

 class MyClass<T>
{
    T field;
    public void myMethod()
    {
       field = (T)new Object(); // works
    }
}
0 голосов
/ 18 ноября 2017

Класс classOfT

        try {
            t = classOfT.newInstance();//new T(); NOTE: type parameter T cannot be instantiated directly
        } catch (Exception e) {
            e.printStackTrace();
        }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...