Как мне сделать тип возвращаемого значения метода универсальным?
Рассмотрим этот пример (типичный для книг по ООП):
У меня есть Animal класс, где у каждого Animal может быть много друзей. И подклассы, такие как Dog, Duck, Mouse и т.д., Которые добавляют специфическое поведение, такое как bark(), quack() и т.д.
Вот некоторый начальный код с типом возвращаемого значения, передаваемым методу в качестве параметра, который никогда не использовался.
public<T extendsAnimal> T callFriend(String name, T unusedTypeObj){ return (T)friends.get(name); }
Есть ли способ определить тип возвращаемого значения во время выполнения без использования дополнительного параметра instanceof? Или, по крайней мере, передав класс этого типа вместо фиктивного экземпляра.
Я понимаю, что generics предназначены для проверки типов во время компиляции, но есть ли обходной путь для этого?
Переведено автоматически
Ответ 1
Вы могли бы определить callFriend таким образом:
public <T extendsAnimal> T callFriend(String name, Class<T> type) { return type.cast(friends.get(name)); }
Преимущество этого кода в том, что он не генерирует никаких предупреждений компилятора. Конечно, на самом деле это всего лишь обновленная версия кастинга времен, предшествовавших появлению generic, и она не добавляет никакой дополнительной безопасности.
Ответ 2
Вы могли бы реализовать это следующим образом:
@SuppressWarnings("unchecked") public <T extendsAnimal> T callFriend(String name) { return (T)friends.get(name); }
Тип возвращаемого значения будет определяться вызывающим объектом. Однако обратите внимание на @SuppressWarnings аннотацию: в ней говорится, что этот код небезопасен для типов. Вы должны проверить это самостоятельно, или вы могли бы получить ClassCastExceptions во время выполнения.
К сожалению, при том способе, которым вы его используете (без присвоения возвращаемого значения временной переменной), единственный способ порадовать компилятор - это вызвать его следующим образом:
jerry.<Dog>callFriend("spike").bark();
Хотя это может быть немного приятнее, чем приведение, вам, вероятно, лучше предоставить Animal классу абстрактный talk() метод, как сказал Дэвид Шмитт.
Ответ 3
Нет. Компилятор не может знать, какой тип jerry.callFriend("spike") вернет. Кроме того, ваша реализация просто скрывает приведение в методе без какой-либо дополнительной безопасности типов. Учтите это:
jerry.addFriend("quaker", newDuck()); jerry.callFriend("quaker", /* unused */newDog()); // dies with illegal cast
В этом конкретном случае создание абстрактного talk() метода и его соответствующее переопределение в подклассах сослужило бы вам гораздо лучшую службу: