我首先要争辩说Serializable和Cloneable是标记接口的不良示例。当然,它们是方法的接口,但它们暗示方法,例如writeObject(ObjectOutputStream)
。(writeObject(ObjectOutputStream)
如果您不覆盖它,则编译器将为您创建一个方法,并且所有对象都已经拥有clone()
,但是编译器将再次创建一个实数clone()
为您方法,但有一些警告。这两种都是奇怪的情况,实际上并不是好的设计示例。)
标记接口通常用于以下两个目的之一:
1)作为避免过长类型的捷径,许多泛型都可能发生这种情况。例如,假设您具有以下方法签名:
public void doSomething(Foobar<String, Map<String, SomethingElse<Integer, Long>>>) { ... }
这很麻烦,而且很难打扰,更重要的是,很难理解。考虑一下这个:
public interface Widget extends Foobar<String, Map<String, SomethingElse<Integer, Long>>> { }
然后您的方法如下所示:
public void doSomething(Widget widget) { ... }
不仅更加清晰,而且您现在可以使用Javadoc Widget接口,并且在Widget代码中搜索所有匹配项也更加容易。
2)标记接口也可以用作解决Java缺少交集类型的一种方式。使用标记器接口,您可以要求某些东西具有两种不同的类型,例如在方法签名中。假设您的应用程序中有一些界面Widget,就像我们上面描述的那样。如果您有一个需要一个Widget的方法,而该Widget也恰巧允许您对其进行迭代(它是人为设计的,但请在此处与我合作),那么您唯一的好解决方案是创建一个扩展两个接口的标记接口:
public interface IterableWidget extends Iterable<String>, Widget { }
在您的代码中:
public void doSomething(IterableWidget widget) {
for (String s : widget) { ... }
}
Serializable
因为注释是胡说八道,@NonNull
而接口则是胡说八道。我会说:注释是标记+元数据。顺便说一句:Annotations的先驱者是XDoclet,他出生于Javadoc,被Annotations杀死。