T
определяется компилятором, смотрящим на контекст вызова этого метода. Если результат вызова должен быть назначен переменной, набранной XXX
, тогда T
будет заменено на XXX
во время компиляции, чтобы проверить логику остальной части кода.
Код вопроса нарушает этот контракт, так как кажется, что код метода контролирует возвращаемый тип, и поэтому он, как правило, не может сделать правильный выбор с точки зрения класса для создания экземпляра. Вот почему этот состав небезопасен.
Способ исправить это - вернуть элемент управления к вызывающему коду. Например, метод get()
может принять объект класса, который указывает возвращаемый тип, и использовать Class.newInstance
для создания объекта с неудобством необходимости обработки соответствующего проверенного исключения и вероятностью того, что запрошенный класс не имеет Конструктор без параметров:
private <T> T get(Class<? extends T> class) {
try {
return class.newInstance();
} catch (Exception ex) {
// handle the exception apropiately
}
}
Телефонный код:
Something some;
if (/* condition 1 */) {
some = get(Something1.class);
} else if (/* condition 2 */) {
some = get(Something2.class);
} ...
Остается вопрос, есть ли у вас общий код, не зависящий от подкласса, для добавления в тело get
до или после создания экземпляра объекта, чтобы сделать этот метод стоящим, в противном случае было бы лучше просто вызвать соответствующий конструктор подкласса в каждом if-else (т.е. new Something1()
, new Something2()
и т. д.).