Могу ли я сохранить атрибут generics в поле объекта - PullRequest
3 голосов
/ 20 ноября 2008

Принимая заглушку следующего класса:

public class Foo<T> {
  private Class<T> type;

  public Foo<T> () {}
}

Могу ли я сохранить универсальный тип T в поле type в конструкторе, не изменяя подпись конструктора на "public Foo<T> (Class<T> type)"?

Если да, то как? Если нет, то почему?

"type = T", похоже, не работает.

Ответы [ 5 ]

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

Нет типа стирания означает, что вы должны предоставить что-то во время выполнения. Вы можете предоставить экземпляр T или Class<T>, но сам класс просто заменит каждый экземпляр T на Object.

Подобные вещи являются одним из самых больших недостатков дженериков Java по сравнению с .NET. (С другой стороны, история отклонений сильнее - если более запутанная - в Java, чем в .NET.)

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

Как сказано в этой теме ,

для списка примеров

list.get (index).getClass() 

будет не даст вам тип объекта, хранящегося в списке:

  • когда список пуст
  • даже когда список НЕ пуст, потому что любой элемент может быть любым подклассом параметра универсального типа.

Так как параметры типа стираются во время компиляции, они не существуют во время выполнения (извините, Джон, в выполнение время ): Следовательно, вы не можете получить информацию общего типа через отражение в java ,

Существует еще один вариант reification , который находится на столе (Java 7?) И будет способствовать тому, что вы ищете.

Можно надеяться, что неверный тип, приведенный к T, вызовет исключение Cast, которое во время выполнения откроет исходный тип, используемый для T, но, увы, оно тоже не работает.

Рассмотрим следующий тестовый класс:

import java.util.ArrayList;

/**
 * @param <T>
 */
public class StoreGerenericTypeInField<T>
{

    private T myT = null;
    private ArrayList<T> list = new ArrayList<T>();

    private void setT(final T aT) { myT = aT; }
    /**
     * Attempt to do private strange initialization with T, in the hope to provoke a cast exception
     */
    public StoreGerenericTypeInField()
    {
        StringBuilder aFirstType = new StringBuilder();
        StringBuffer aSecondType = new StringBuffer();
        this.list.add((T)aFirstType);
        this.list.add((T)aSecondType);
        System.out.println(this.list.get(0).getClass().getName());
        System.out.println(this.list.get(1).getClass().getName());

        setT((T)aFirstType);
        System.out.println(this.myT.getClass().getName());
        setT((T)aSecondType);
        System.out.println(this.myT.getClass().getName());
    }
    /**
     * @param args
     */
    public static void main(String[] args)
    {
        StoreGerenericTypeInField<Integer> s = new StoreGerenericTypeInField<Integer>();
    }
}

Конструктор пытается сохранить неприятные вещи в своей переменной T (или в своем списке T) ... и все работает гладко!?

Он печатает:

java.lang.StringBuilder
java.lang.StringBuffer
java.lang.StringBuilder
java.lang.StringBuffer

Сам по себе тип стирания не виноват ... это комбинация типа стирания (новичок в java) и небезопасное приведение (устаревшая функция Java), которая делает T действительно недоступным во время выполнения (до тех пор, пока вы на самом деле не попробуете использовать его с * T 'специальными методами)

1 голос
/ 20 ноября 2008

Ну, почему бы не иметь экземпляр T в вашем классе? Я имею в виду, что Т покупает тебе что-нибудь, если это не так? Так что, если у вас есть T x, они вам поменяют x.GetType ().

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

Вы должны попробовать это возможно:

type = T.GetType();
0 голосов
/ 20 ноября 2008

ли

type = T.getClass();

работа

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