Екземпляр об'єкта типу параметра


89

Я отримав клас шаблону таким чином:

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

Як створити новий екземпляр T у своєму класі?

Відповіді:


86

Після стирання типу відомо 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)` повинен оголосити `викидає NoSuchMethodException` для компіляції. На жаль, ваша відповідь не є доброзичливою для початківців Java.
пурукат

@ user927387java.util.function.Supplier
erickson

Постачальник <T> вимагає Java 8, JFTR там, де це варто.
Fran Marzoa

14

Іншим невідбиваючим підходом є використання гібридного шаблону 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 вийшли.


12

Це може бути більш важкою вагою, ніж те, що ви шукаєте, але це також буде працювати. Зверніть увагу, що якщо ви застосуєте такий підхід, було б більш розумно вводити завод у MyClass, коли він побудований, замість того, щоб передавати його у ваш метод кожного разу, коли він викликається.

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

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

1
Хороший, невідбиваючий підхід; рефлексія не завжди є варіантом. myMethod повинен мати можливість приймати MyFactory <? поширюється T>, так?
erickson

1
Хороший дзвінок - ви захочете поставити обмежений узагальнюючий знак на заводі, щоб дозволити створювати об’єкти типу T і підкласи T в myMethod ().
Ден Ходж,


-3

Клас classOfT

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

2
Де оголошено клас classOfT?
Фран Марцоа
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.