Java中的标记接口
标记接口
标记接口是内部没有任何方法或常量的接口。它提供有关对象的运行时类型信息,因此编译器和 JVM 具有有关该对象的附加信息。
早起的Java版本中,标记接口主要用来提供一种方法像编译器或者运行时发出信号,表示某个类具有特殊属性。而且大多时候都是底层框架提供,并且同时实现检查。
常见示例
Java中内置的常见标记接口,比如Serializable、Cloneable和 Remote。
- 当实现了Serializable接口,表示当前类的对象是可以被序列化和反序列化处理的,也就是说可以被ObjectOutputStream、ObjectInputStream里读取和写入的。
- 如果一个类没有实现序列化接口,却当成序列化对象传入,此时就会异常。【需要注意的是,ObjectOutputStream、ObjectInputStream接受的参数是Object类型,并不是Serializable类型,因此出只会在运行时才会异常;假设如果接收的只允许Serializable类型是不是更好,这样在编译时,如果传入的类没有实现序列化接口,IDE就会直接提示,编译不通过,而不是讲问题带到运行时才发现呢】
package java.io;
public interface Serializable {
}
package java.lang;
public interface Cloneable{
}
- Cloneable而言,如果我们尝试克隆未实现此接口的对象,JVM 将抛出CloneNotSupportedException。因此,Cloneable 标记接口是向 JVM 发出的一个指示 ,表示我们可以调用Object.clone()方法【同样的,因为clone是Object类中提供的方法,检查是否可以被克隆,是在运行时抛出异常的】
- Spring中也有标记接口,属于顶层接口类,最常见的就是Aware。它作为一个顶级标记接口只是做限制,具体的Aware子接口继承它并定义自己的接口方法声明。
/** * 一个标记超接口,指示bean有资格通过回调样式的方法由特定框架对象的Spring容器通知。实际的方法签名由各个子接口决定,但通常应该只包含一个接受单个参数的空返回方法。 注意,仅仅实现Aware不提供默认功能。相反,处理必须显式地完成 * */ public interface Aware { }
标记接口的优势
- 标记接口定义的类型是由被标记的类的实例实现的,相对于注解而言,标记接口的限定,在编译时就能发现错误,而注解只有在运行时才能发现。
- 标记接口的可读性更强,意义更加的明确,更符合面向对象编程的多态性实现。无论是作为参数、变量,在判断某个对象是否是某个接口声明时,和判断普通对象并无二致,使用instanceof关键字即可。注解测需要通过注解解析器解析。
- 标记接口侧重于行为,或者从广义上限定某种类型。注解侧重于属性,以及携带元数据和更多注解信息。依据实际情况而做出设计,两者并不冲突,也不能完全替代。
一个小示例
-
声明一个标记接口,作用很简单,只是说明继承它接口、实现它的类可以被作为一个“机器人”
public interface Robot{}
-
业务方法中使用,假设发现是个“机器人实例”就要被回收,而不是直接销毁
public class ToyDestoryService{ public void destory(Object obj){ if(obj instanceof Robot){ System.out.print("机器人暂不彻底销毁..."); } else{ System.out.print("彻底摧毁."); } } }