Java: создать объект, тип которого является параметром типа - PullRequest
7 голосов
/ 06 июля 2011

Я хочу написать эквивалентный код Java для кода C #.

Мой код C # выглядит следующим образом:

public abstract class A<T> where T : A<T>, new()
{
    public static void Process()
    {
        Process(new T());
    }

    public static void Process(T t)
    {
        // Do Something...
    }
}

public class B : A<B>
{
}

public class C : A<C>
{
}

Java-код моего кода выглядит следующим образом.

public abstract class A<T extends A<T>>
{
    public static <T extends A<T>> void process()
    {
        process(new T()); // Error: Cannot instantiate the type T 
    }

    public static <T extends A<T>> void process(T t)
    {
        // Do Something...
    }

    public class B extends A<B>
    {
    }

    public class C extends A<C>
    {
    }
}

Здесь синтаксис "new ()" в объявлении класса заставляет производные классы написать конструктор по умолчанию, который позволяет вызывать "new T ()" из базового класса. Другими словами, когда я пишу базовый класс, я уверен, что у производного класса будет конструктор по умолчанию, так что я могу создать экземпляр объекта производного класса из базового класса.

Моя проблема в Java - я не могу создать экземпляр объекта производного класса из суперкласса. Я получаю "Cannot instantiate the type T" ошибку для "new T()" звонка. Есть ли в Java аналогичный C # способ или я должен использовать что-то вроде шаблона прототипа и клонирования?

Ответы [ 6 ]

5 голосов
/ 06 июля 2011

Java не поддерживает улучшенные обобщенные значения , поэтому нет эквивалента "new T();".Чтобы обойти это, я использую отражение против токена типа.Маркер типа указывает, что является универсальным типом.

public abstract class A<T> {
  private Class<T> typeToken;
  // constructor
  public A() {
        typeToken = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
  }
}

Затем используйте отражение для создания экземпляра класса.Это некрасиво, но это делает работу.

2 голосов
/ 06 июля 2011

Вы можете найти некоторое объяснение разницы между дженериками в C # и Java от this li nk - сравнение дженериков Java и C # .

Обобщения Java - это полностью конструкция времени компиляции. Вы не можете ничего сделать с параметрами общего типа, которые каким-либо образом зависят от информации времени выполнения. Это включает в себя:

  • Создание экземпляров универсального типа параметры.
  • Создание массивов универсального типа параметры.
  • Запрос класса времени выполнения параметр универсального типа.
  • Использование instanceof с универсальным типом параметры.

Вы можете обойти это ограничение с помощью java.lang.reflect namepsace. Например, посмотрите на этот вопрос:

0 голосов
/ 07 июля 2011

На самом деле это не проблема в Java.Идиома передает класс

    public static <T extends A<T>> T process(Class<T> clazz) 
    {
        T o = clazz.newInstance();
        process( o ); 
        return o;
    }

    X x = process(X.class); // not too verbose

Я добавил возвращаемое значение, чтобы проиллюстрировать общий случай.

0 голосов
/ 06 июля 2011

В дополнение к другим комментариям я бы предложил не использовать дженерики. Они не нужны - они все равно удаляются во время компиляции - и если вы не знаете их хорошо, вы попытаетесь заставить их делать то, что они не могут.

Как только ваш класс будет работать должным образом, , а затем добавьте их обратно. В этот момент ваша IDE даст вам много полезных и понятных советов, а обобщения будут предупреждать вас, когда вы используете объекты неправильного класса.

Мне кажется возможным, что этот класс вообще не будет нуждаться в генериках после завершения. (Я не знаю, что еще может делать этот класс, и я не понимаю использования статических методов - у них никогда не будет доступа к информации о типе отдельного экземпляра.)

0 голосов
/ 06 июля 2011

Просто используйте стандартный болотный шаблон Abstract Factory.Затем вы получаете дополнительные преимущества, которые вы не привязываете к конкретному типу, у типа реализации нет необходимости иметь конкретный конструктор, у экземпляра может быть некоторая параметризация, экземпляры могут кэшироваться и т. Д. И т. Д.

Ради любви к Богу, не используйте отражение.

0 голосов
/ 06 июля 2011

Также остерегайтесь этого, если вы используете дженерики.

T[] someArray = new T[];

Это одна из причин предпочитать ArrayList массивам. Причина проблемы заключается в переопределении и стирании типов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...