我理解接口是类的契约,如果类实现了接口,那么接口中的所有方法都必须在类中。
以下是涉及此question的接口的示例,这让我感到困惑:
public class Contact implements Comparable<Contact> {
private String name;
public int compareTo(Contact other) {
return name.compareTo(other.name);
}
}
然后,您可以显然创建ArrayList
并按名称对其进行排序。
List<Contact> contacts = new ArrayList<Contact>();
Collections.sort(contacts);
但如果Contract
没有这样实现Comparable
:
public class Contact {
private String name;
public int compareTo(Contact other) {
return name.compareTo(other.name);
}
}
即使Collections.sort
方法仍然存在,调用compareTo
也会出现编译时错误。
显然,实现接口可以提供额外的功能。除了强制执行结构之外,接口的目的是什么?
答案 0 :(得分:1)
因为如果Contact implements Comparable<Contact>
,则Contact
是 Comparable<Contact>
。
让我们来看看源代码,在ComparableTimSort.countRunAndMakeAscending()
的深处有一行:
if (((Comparable) a[runHi++]).compareTo(a[lo]) < 0)
相关位是((Comparable) a[runHi++])
- a[runHi++]
强制到Comparable
,然后在上调用compareTo
为a Comparable
。
所以如果Contact implements Comparable<Contact>
我可以这样做:
final Comparable<Contact> contact = new Contact();
如果没有,那么我显然无法将实例分配给Comparable
类型,因此我不知道(不使用反射)Contact
有哪些方法。
通过实现Comparable
我告诉编译器这个类是 Comparable
因此可以在必要时被视为一个。必须实施这些方法只是其副作用。
至于为什么编译时而不是运行时错误,您只需要查看方法Collections.sort
的声明即可找到:
public static <T extends Comparable<? super T>> void sort(List<T> list)
所以这个方法是generic method,它的签名要求List<T>
T extends Comparable<? super T>
。这让我们分解一下有点棘手。
我们需要T
到extends Comparable<? super T>
。因此T
需要implements Comparable<? super T>
或Comparable
的某些子类。 ? super T
表示Comparable
类型T
或任何超类型可以是compareTo
- 即如果您的Object
可以排序T
,那么它也可以对{{1}}进行排序(通过Liskov替换原则)。
答案 1 :(得分:0)
上面的答案是技术问题,但从设计的角度来看,它们在程序层之间创建了一层抽象。这在设计复杂系统时很重要,因为它减少了类之间的依赖关系,并允许更高的可维护性。
答案 2 :(得分:0)
其他答案给出了更常见的接口用法。我还在考虑另外两个:
Serializable
不包含任何方法,也不包含常量,只是声明可以将类的实例成功序列化为流并反序列化。Proxy
只能代理接口。因此,要代理类,必须首先将其公共方法导出到一个或多个接口。它通常用在Spring框架AOP中。