Java Generic Interface vs Generic Methods, и когда использовать один
мне было интересно, помимо синтаксической разницы, когда можно использовать общий интерфейс над методом, который принимает общий параметр?
public interface Flight<T>{
void fly(T obj);
}
над
public interface Flight{
void <T> fly(T obj);
}
3 ответов
если вы объявите общий метод, вы всегда позволяете абонента решите, какие аргументы использовать для параметров типа. Реализация метода должна иметь возможность обрабатывать все возможные аргументы типов (и у нее даже нет способа запросить фактические аргументы типа).
тем не менее, такой метод, как <T> void fly(T obj); указано, что абонент может использовать любой тип для T пока единственное, на что может положиться реализация, это то, что фактический тип для T будет назначить Object (как если <T extends Object> была объявлена).
таким образом, в этом конкретном примере это не отличается от объявления void fly(Object obj);, что также позволяет произвольным объектам.
напротив, параметр типа на interface является частью договора и может быть указан или ограничен реализация на interface:
public interface Flight<T>{
void fly(T obj);
}
позволяет реализациям как
public class X implements Flight<String> {
public void fly(String obj) {
}
}
фиксация типа T на стороне реализации. Или
public class NumberFlight<N extends Number> implements Flight<N> {
public void fly(N obj) {
}
}
будучи по-прежнему общим, но ограничения тип.
подпись interface также важно, когда interface сам является частью другой сигнатуры метода, например
public void foo(Flight<? super String> f) {
f.fly("some string value");
}
здесь Flight реализация, которую вы переходите к foo, должен быть способен потреблять String значение, поэтому Flight<String> или Flight<CharSequence> или Flight<Object> достаточно, но не Flight<Integer>. Для объявления такого контракта требуются параметры типа на interface, не на interface’ы методов.
вы должны использовать универсальный тип, когда ожидаете, что большинство методов в реализациях будут выполнять операции над типом, предоставленным при создании экземпляра класса.
например, ArrayList<E> является универсальным типом, так как большинство его операций (add, get, remove и т. д.) полагаться на тип, указанный при создании одного.
общий метод должен использоваться, когда только несколько методов в классе полагаться на различные типы.
вы можете прочитать больше о дженерики в Java Docs.
возьмите, например, класс java.util.ArrayList<E>. При создании переменных этого типа необходимо указать конкретный тип для T:
ArrayList<String> list = new ArrayList<>();
эти конкретные типы используются при вызове методов из List интерфейс, который работает с типом T. Вызываю add метод, вы можете только добавить String объекты в список. Извлечение элементов из списка с помощью get, вы получите элементы конкретного типа String.
для общих методов, тип T указывается только для этого метода. И было бы более разумно, если бы методы возвращали значение этого общего типа. Вы часто находите такой код:
MyObject obj = SomeClass.staticGenericMethod(MyObject.class)
или
MyObject obj = classInstance.genericMethod(MyObject.class);
и вы должны начать свое имя интерфейса с заглавной буквы:Flight<T>