在jdk的源碼中,存在這樣的一些接口,他們不包含任何的(抽象)方法,但是卻廣泛的存在。
這種接口我們稱(chēng)之為Mark Interface,也就是標記接口。
這些接口呢,我們不用來(lái)實(shí)現任何的方法,他們的作用就是當某個(gè)類(lèi)實(shí)現這個(gè)接口的時(shí)候,我們就認為這個(gè)類(lèi)擁有了這個(gè)接口標記的某種功能了。
下面通過(guò)三個(gè)例子,分別介紹java中常用的三個(gè)標記接口:
RandomAccess 、Cloneable、java.io.Serializable
(1)RandomAccess
在C#中經(jīng)常會(huì )有很多人在爭論,在遍歷集合時(shí),到底是應該用for還是用foreach。
在Java中,卻完全不用再糾結這個(gè)問(wèn)題:
java中有這樣一個(gè)接口
這個(gè)接口的作用是判斷集合是否能快速訪(fǎng)問(wèn)的。也就是傳入一個(gè)Index后,指針能否快速的移動(dòng)到對應的元素上,還是需要像訪(fǎng)問(wèn)隊列一樣依次移動(dòng)到指定元素上。
如果我們在實(shí)現某個(gè)容器類(lèi)時(shí),容器(防盜連接:本文首發(fā)自http://www.cnblogs.com/jilodream/ )中的元素可以通過(guò)index快速的訪(fǎng)問(wèn)到(一般核心的存儲接口是使用數組),那么你在該類(lèi)的定義處,就可以像ArrayList這樣打上一個(gè)RandomAccess接口的實(shí)現標簽:
在使用的過(guò)程中,通過(guò)判斷是否實(shí)現RandomAccess接口,就可以決定采取哪種遍歷的方式了。
如下:
這樣針對于不同的List采取不同的遍歷形式,可以讓遍歷的速度更快。
(2)Cloneable
這個(gè)接口大家都非常熟悉,在深度拷貝的時(shí)候,常常用到該接口。這個(gè)接口也是一個(gè)標記接口:
他的作用是標記該對象的是否擁有克隆的能力。很多認或許會(huì )覺(jué)得疑惑,Object類(lèi)本身就已經(jīng)實(shí)現了 protectednativeObject clonethrowsCloneNotSupportedException;
方法
按道理來(lái)說(shuō)每一個(gè)類(lèi)都應該可以運行clone方法的,為什么還需要打上這樣一個(gè)接口。這樣的好處是以接口的形式標記對象是否擁有某種能力。想一想,倘若不通過(guò)標記接口的形式,我們在平常的工作中,如何實(shí)現呢?一般來(lái)說(shuō)都是通過(guò)設定枚舉,或者增加變量來(lái)控制。這樣或許能解決問(wèn)題,但是往往不能從面向對象的角度來(lái)優(yōu)雅的解決問(wèn)題。
想想接口的作用是什么吧?接口就是用來(lái)標記某個(gè)類(lèi)擁有了哪些功能、特性。而標記接口則是在面向對象的角度來(lái)看,更高層級的一種抽象:即使你擁有這個(gè)方法也不行,因為你沒(méi)有這個(gè)功能的標記接口。
所以在調用的clone的過(guò)程中,倘若對象沒(méi)有實(shí)現Cloneable 接口,那么虛擬就會(huì )拋出一個(gè)CloneNotSupportedException,不支持的clone的異常。
(3)java.io.Serializable
這個(gè)接口是用來(lái)標記類(lèi)是否支持序列化的。所謂的序列化就是將對象的各種信息轉化成可以存儲或者傳輸的一種形式。我記得我剛參加工作的時(shí)候,對這個(gè)序列化非常難以理解,覺(jué)得server返回一個(gè)對象,client接收即可,為什么總要(防盜連接:本文首發(fā)自http://www.cnblogs.com/jilodream/ )序列化,反序列化的折騰。后來(lái)leader告訴我這是因為很多時(shí)候,由于通信協(xié)議的原因,在傳輸的過(guò)程中,復雜的類(lèi)對象是不支持傳來(lái)傳去的,所以一般來(lái)說(shuō)要轉化成流的形式,放在包中傳來(lái)傳去。言歸正傳,java.io.Serializable和Cloneable 接口一樣,倘若一個(gè)類(lèi)沒(méi)有實(shí)現該接口,而被拿去序列化,虛擬機就會(huì )拋出不支持的異常,盡管從代碼的調用來(lái)說(shuō),不存在任何問(wèn)題。
請看java源碼中的第二個(gè)注釋?zhuān)粋€(gè)將要被序列化,但是未實(shí)現序列化接口的Object:
Exceptions are thrown for problems with the OutputStream and for11 * classes that should not be serialized. All exceptions are fatal to the12 * OutputStream, which is left in an indeterminate state, and it is up to13 * the caller to ignore or recover the stream state.14 *15 * @throws InvalidClassException Something is wrong with a class used by16 * serialization.17 * @throws NotSerializableException Some object to be serialized does not18 * implement the java.io.Serializable interface.19 * @throws IOException Any exception thrown by the underlying20 * 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 }
至此,通過(guò)三種常用的標記接口,應該已經(jīng)闡述清標記接口的使用情況了,個(gè)人認為這是一種非常抽象的面向對象的方式。即只通過(guò)向對象以添加標簽的形式,來(lái)標記這個(gè)對象可以或不可以實(shí)現某種功能,這要比直接定義變量或枚舉,要優(yōu)雅的多。
聯(lián)系客服