在 jdk 的源码中,存在这样的一些接口,他们不包含任何的(抽象)方法,但是却广泛的存在。
这种接口我们称之为 Mark Interface,也就是标记接口。
这些接口呢,我们不用来实现任何的方法,他们的作用就是当某个类实现这个接口的时候,我们就认为这个类拥有了这个接口标记的某种功能了。
下面通过三个例子,分别介绍 java 中常用的三个标记接口:
RandomAccess 、Cloneable、java.io.Serializable
(1)RandomAccess
在 C# 中经常会有很多人在争论,在遍历集合时,到底是应该用 for 还是用 foreach。
在 Java 中,却完全不用再纠结这个问题:
java 中有这样一个接口
- 1 public interface RandomAccess {
- 2
- }
这个接口的作用是判断集合是否能快速访问的。也就是传入一个 Index 后,指针能否快速的移动到对应的元素上,还是需要像访问队列一样依次移动到指定元素上。
- 1 public class ArrayListextends AbstractList 2 implements List,
- RandomAccess,
- Cloneable,
- java.io.Serializable 3 {
- 4 //...
- 5
- }
- 6而LinkedList就没有实现该标记接口7 public class LinkedList 8 extends AbstractSequentialList 9 implements List,
- Deque,
- Cloneable,
- java.io.Serializable 10 {
- 11 //...
- 12
- }
在使用的过程中, 通过判断是否实现 RandomAccess 接口,就可以决定采取哪种遍历的方式了。
如下:
- 1 import java.util.List;
- 2 import java.util.RandomAccess;
- 3 4 public class SourceLearning 5 {
- 6 public void iteratorElements(List list) 7 {
- 8
- if (list instanceof RandomAccess) 9 {
- 10
- for (int i = 0, size = list.size(); i < size; i++) 11 {
- 12 String element = list.get(i);
- 13
- }
- 14
- }
- 15
- else 16 {
- 17
- for (String element: list) 18 {
- 19
- }
- 20
- }
- 21
- }
- 22
- }
这样针对于不同的 List 采取不同的遍历形式,可以让遍历的速度更快。
(2)Cloneable
这个接口大家都非常熟悉,在深度拷贝的时候,常常用到该接口。这个接口也是一个标记接口:
- 1 public interface Cloneable {
- 2
- }
他的作用是标记该对象的是否拥有克隆的能力。很多认或许会觉得疑惑,Object 类本身就已经实现了 protected native Object clone() throws CloneNotSupportedException;
方法
按道理来说每一个类都应该可以运行 clone 方法的,为什么还需要打上这样一个接口。这样的好处是以接口的形式标记对象是否拥有某种能力。想一想,倘若不通过标记接口的形式,我们在平常的工作中,如何实现呢?一般来说都是通过设定枚举,或者增加变量来控制。这样或许能解决问题,但是往往不能从面向对象的角度来优雅的解决问题。
想想接口的作用是什么吧?接口就是用来标记某个类拥有了哪些功能、特性。而标记接口则是在面向对象的角度来看,更高层级的一种抽象:即使你拥有这个方法也不行,因为你没有这个功能的标记接口。
所以在调用的 clone 的过程中,倘若对象没有实现 Cloneable 接口,那么虚拟就会抛出一个 CloneNotSupportedException,不支持的 clone 的异常。
(3)java.io.Serializable
这个接口是用来标记类是否支持序列化的。所谓的序列化就是将对象的各种信息转化成可以存储或者传输的一种形式。我记得我刚参加工作的时候,对这个序列化非常难以理解,觉得 server 返回一个对象,client 接收即可,为什么总要序列化,反序列化的折腾。后来 leader 告诉我这是因为很多时候,由于通信协议的原因,在传输的过程中,复杂的类对象是不支持传来传去的,所以一般来说要转化成流的形式,放在包中传来传去。言归正传,java.io.Serializable 和 Cloneable 接口一样,倘若一个类没有实现该接口,而被拿去序列化,虚拟机就会抛出不支持的异常,尽管从代码的调用来说,不存在任何问题。
请看 java 源码注释中的第二个抛出异常:一个将要被序列化,但是未实现序列化接口的 Object:
- 1
- /**
- 2 * Write the specified object to the ObjectOutputStream. The class of the
- 3 * object, the signature of the class, and the values of the non-transient
- 4 * and non-static fields of the class and all of its supertypes are
- 5 * written. Default serialization for a class can be overridden using the
- 6 * writeObject and the readObject methods. Objects referenced by this
- 7 * object are written transitively so that a complete equivalent graph of
- 8 * objects can be reconstructed by an ObjectInputStream.
- 9 *
- 10 * <p>Exceptions are thrown for problems with the OutputStream and for
- 11 * classes that should not be serialized. All exceptions are fatal to the
- 12 * OutputStream, which is left in an indeterminate state, and it is up to
- 13 * the caller to ignore or recover the stream state.
- 14 *
- 15 * @throws InvalidClassException Something is wrong with a class used by
- 16 * serialization.
- 17 * @throws NotSerializableException Some object to be serialized does not
- 18 * implement the java.io.Serializable interface.
- 19 * @throws IOException Any exception thrown by the underlying
- 20 * OutputStream.
- 21 */
- 22 public final void writeObject(Object obj) throws IOException {
- 23
- if (enableOverride) {
- 24 writeObjectOverride(obj);
- 25
- return;
- 26
- }
- 27
- try {
- 28 writeObject0(obj, false);
- 29
- } catch(IOException ex) {
- 30
- if (depth == 0) {
- 31 writeFatalException(ex);
- 32
- }
- 33
- throw ex;
- 34
- }
- 35
- }
来源: http://www.cnblogs.com/jilodream/p/5986519.html