Java 泛型接口与泛型方法,以及何时使用其中一种
Posted
技术标签:
【中文标题】Java 泛型接口与泛型方法,以及何时使用其中一种【英文标题】:Java Generic Interface vs Generic Methods, and when to use one 【发布时间】:2015-08-15 00:38:41 【问题描述】:我想知道,除了句法差异之外,什么时候可以在接受泛型参数的方法上使用泛型接口?
public interface Flight<T>
void fly(T obj);
结束
public interface Flight
void <T> fly(T obj);
【问题讨论】:
您是否希望实现flight
的实例能够在fly
方法中仅处理一种选定类型的数据或任何类型的数据?
【参考方案1】:
以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>
【讨论】:
【参考方案2】:如果你声明一个通用的方法,你总是让调用者来决定哪些类型参数用于类型参数。该方法的实现必须能够处理所有可能的类型参数(它甚至没有办法请求实际的类型参数)。
也就是说,像<T> void fly(T obj);
这样的方法声明调用者可以使用T
的任何类型,而实现唯一可以依赖的是T
的实际类型将可分配给Object
(就像 <T extends Object>
已被声明)。
所以在这个具体的例子中,它与声明 void fly(Object obj);
没有什么不同,它也允许任意对象。
相比之下,interface
上的类型参数是合同的一部分,可以由interface
的实现 指定或限制: p>
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");
在这里,您传递给foo
的Flight
实现必须能够使用String
值,因此Flight<String>
或Flight<CharSequence>
或Flight<Object>
就足够了,但Flight<Integer>
就足够了.声明这样的合约需要interface
的类型参数,而不是interface
的方法。
【讨论】:
因此,使用通用接口方法而不是通用方法仍然归结为设计决策。这是有道理的,将泛型类型添加到等式中并不会真正改变方法和接口的功能,尽管它增加了某些功能,例如类型限制。NumberFlight
甚至可以在不改变Flight
和<T>
之间的契约的情况下限制类型。那很有意思。我现在更开明了,非常感谢!【参考方案3】:
当您期望实现中的大多数方法将对实例化类时提供的类型执行操作时,您应该使用泛型类型。
例如,ArrayList<E>
是一种泛型类型,因为它的大部分操作(添加、获取、删除等)都依赖于创建时指定的类型。
当类中只有少数方法依赖于不同类型时,应使用泛型方法。
您可以在Java Docs 中阅读有关泛型的更多信息。
【讨论】:
以上是关于Java 泛型接口与泛型方法,以及何时使用其中一种的主要内容,如果未能解决你的问题,请参考以下文章