Java中的标记
接口(Marker Interface),又称标签接口(Tag Interface),具体是不包含任
何方法的接口。
在Java中很容易找到标记接口的
例子,比如JDK中的Serialzable接口就是一个标记接口。
首先要明确的是,标记接口并不是Java语言独有的,而是计算机科学中的一种通用的设计理念。
class="java" name="code">
The tag/marker interface pattern is a design pattern in computer science, used with languages that provide run-time type information about objects. It provides a means to associate metadata with a class where the language does not have explicit support for such metadata.
上面这段话是维基百科对标记接口的定义。
具体说的就是,标记接口是计算机科学中的一种设计思路,用于给那些面向对象的
编程语言描述对象。因为编程语言本身并不支持为类维护元数据,而标记接口可以用作描述类的元数据,弥补了这个功能上的缺失。对于实现了标记接口的类,我们就可以在运行时通过
反射机制去获取元数据。
以Serializable接口为例,如果一个类实现了这个接口,则表示这个类可以被序列化。因此,我们实际上是通过了Serializable这个接口给该类标记了【可被序列化】的元数据,打上了【可被序列化】的标签。这也是标记/标签接口名字的由来。
具体在Java中,标记接口主要有以下两种目的:
1.
建立一个公共的父接口。比如EventListener接口,一个由几十个其它接口扩展的Java API,当一个接口继承了EventListener接口,Java虚拟机(
JVM)就知道该接口将要被用于一个事件的代理方案。同样的,你可以使用一个标记接口来建立一组接口的父接口。
2.
向一个类添加数据类型。这种情况是标记接口最初的目的,实现标记接口的类不需要定义任何接口方法(因为标记接口根本就没有方法),但是该类通过Java的多态性可以变成一个接口类型。
更多的,一些容器例如Ejb容器,
Servlet容器或运行时环境依赖标记接口识别类是否需要进行某种处理,比如Serialialbe接口标记类需要进行序列化操作。
当然了,在现在Spring流行的时代,
注解(
Annotation)已经成为了最好的维护元数据的方式。因为注解能声明在包、类、字段、方法、局部变量、方法参数等之上,既灵活又方便地起到维护元数据的目的。
然而注解这么好的东西,只有在JDK1.5之后才能用。JDK1.5之前维护元数据的重任就落在标记接口的肩膀上了。可以看看另一个标记接口Cloneable的源码,里面的
注释清晰地标注了该接口从JDK1.0的时代就有了
package java.lang;
/**
* @author unascribed
* @see java.lang.CloneNotSupportedException
* @see java.lang.Object#clone()
* @since JDK1.0
*/
public interface Cloneable {
}
这时候,如果一个类没有实现Cloneable接口,在执行clone方法时JVM就会抛出CloneNotSupportedException
异常。
另外的,可以使用
instanceof
关键字运算符来进行类型查询。
if (obj instanceof Cloneable) {
// do something...
}
最后列举出Java源码中几个标记接口的优秀例子。
java.io.Serializable:未实现此接口的类将无法使其任何状态序列化或
反序列化。为保证serialVersionUID值跨不同Java编译器实现的一致性,序列化类必须声明一个明确的 serialVersionUID值。
java.lang.Cloneable:表明Object.clone()方法可以合法地对该类实例进行按字段复制。实现此接口的类应该使用公共方法重写Object.clone(它是受保护的)。如果在没有实现 Cloneable接口的实例上调用Object的clone()方法,则会导致抛出CloneNotSupportedException异常。
java.util.RandomAccess:用来表明其支持快速(通常是固定时间)随机访问。此接口的主要目的是允许一般的
算法更改其行为,从而在将其应用到随机或连续访问列表时能提供良好的性能。
java.rmi.Remote:Remote接口用于标识其方法可以从非本地虚拟机上调用的接口。任何
远程对象都必须直接或间接实现此接口。只有在远程接口(扩展java.rmi.Remote的接口)中指定的这些方法才可远程使用。