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>