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

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

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

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

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
96
0
65 825
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 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();
  }

}

В каком пакете находится Supplier? `MyClass (Class <? Extends T> impl)` должен объявлять `throws NoSuchMethodException` для компиляции. К сожалению, ваш ответ не подходит для новичков в Java.

purucat 12.09.2016 05:45

@ user927387 java.util.function.Supplier

erickson 12.09.2016 05:46

Поставщик <T> требует Java 8, JFTR везде, где стоит.

Fran Marzoa 12.03.2018 16:02

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

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

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

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

Хороший, неотразимый подход; отражение - не всегда вариант. myMethod должен иметь возможность принимать MyFactory <? расширяет T>, верно?

erickson 19.11.2008 03:20

Хороший прием - вы захотите поместить в фабрику ограниченный подстановочный знак, чтобы разрешить создание объектов типа T и подклассов T в myMethod ().

Dan Hodge 20.11.2008 05:49

Другой неотражающий подход - использовать гибридный паттерн Строитель / Абстрактная фабрика.

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

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

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

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

Класс classOfT

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

Где объявлен этот класс classOfT?

Fran Marzoa 12.03.2018 16:24

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

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

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

Другие вопросы по теме