Java 通用接口与通用方法,以及何时使用它们

Java Generic Interface vs Generic Methods, and when to use one

我想知道,除了语法差异之外,什么时候会在接受通用参数的方法上使用通用接口?

public interface Flight<T>{
   void fly(T obj);
}

超过

public interface Flight{
    void <T> fly(T obj);
}

当您期望实现中的大多数方法将对实例化 class 时提供的类型执行操作时,您应该使用泛型类型。

例如,ArrayList<E> 是一种通用类型,因为它的大部分操作(添加、获取、删除等)都依赖于创建一个时指定的类型。

当 class 中只有少数方法依赖于不同类型时,应使用通用方法。

您可以在 Java Docs 中阅读有关泛型的更多信息。

如果您声明一个泛型 方法 ,您总是让 调用者 决定将哪种类型参数用于类型参数。该方法的实现必须能够处理所有可能的类型参数(它甚至没有办法请求实际的类型参数)。

就是说,像 <T> void fly(T obj); 这样的方法声明调用者可以为 T 使用任何类型,而实现唯一可以依赖的是 T 的实际类型将可分配给 Object(就像 <T extends Object> 已声明)。

所以在这个具体的例子中,它与声明void fly(Object obj);没有什么不同,它也允许任意对象。

相比之下,interface 上的类型参数是契约的一部分,可以由 实现[=58] 指定或限制=] 的 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");
}

此处,传递给 fooFlight 实现必须能够使用 String 值,因此 Flight<String>Flight<CharSequence>Flight<Object> 就足够了,但 Flight<Integer> 就不够了。声明这样的合同需要 interface 上的类型参数,而不是 interface 的方法。

以class java.util.ArrayList<E>为例。创建该类型的变量时,必须为 T:

指定具体类型
ArrayList<String> list = new ArrayList<>();

当从 List 接口调用方法时,使用这些具体类型,它们与类型 T 一起工作。调用add方法,只能将String个对象添加到列表中。使用 get 从列表中检索元素,您将获得具体类型 String.

的元素

对于泛型方法,仅为此方法指定类型 T。如果方法 returns 是该泛型类型的值,那将更有意义。您经常会发现这样的代码:

MyObject obj = SomeClass.staticGenericMethod(MyObject.class)

MyObject obj = classInstance.genericMethod(MyObject.class);

您的接口名称应该以大写字母开头:Flight<T>