我首先会争辩说 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 缺乏交集类型的问题。使用标记接口,您可以要求某些内容具有两种不同的类型,例如在方法签名中。假设您的应用程序中有一些界面小部件,就像我们上面描述的那样。如果您有一个需要一个小部件的方法,该小部件也恰好让您对其进行迭代(它是人为的,但在这里与我合作),您唯一的好解决方案是创建一个扩展两个接口的标记接口:
public interface IterableWidget extends Iterable<String>, Widget { }
在您的代码中:
public void doSomething(IterableWidget widget) {
for (String s : widget) { ... }
}