你好,你的問(wèn)題包含了兩個(gè)小問(wèn)題,①java設計interface的原因?②是不是為了盡可能替代類(lèi)的繼承?
接口與繼承分別是什么?(定義)接口是一系列方法的聲明,比如方法名、參數、返回值等信息,接口中的方法不實(shí)現,這些方法可以在不同的地方被不同的類(lèi)實(shí)現。
繼承就是子類(lèi)繼承父類(lèi)的特征和行為,使得子類(lèi)具有父類(lèi)的實(shí)例域和方法。
接口與繼承的設計原因是什么?(用處)接口的主要作用在于降低代碼的耦合度,屏蔽實(shí)現層,比如前后端接口交互的時(shí)候,大家約定好接口層就可以互不影響的干活了,至于接口實(shí)現后端可以慢慢做。
繼承的主要作用在于,在已有基礎上繼續進(jìn)行功能的擴充①清晰體現相關(guān)類(lèi)間的層次結構關(guān)系②減小代碼的冗余度,大大增加程序的重用性。
接口與繼承有什么區別?①定義的修飾符不同(interface),(extends)
②接口中只能定義全局常量和抽象方法,而在繼承中可以定義屬性方法,變量,常量等。
③接口被類(lèi)實(shí)現時(shí),在類(lèi)中一定要實(shí)現接口中的所有方法,而繼承可以調用指定方法。
④繼承只能繼承一個(gè)類(lèi),但implements可以實(shí)現多個(gè)接口,用逗號分開(kāi)就行了 。
綜上所述,java中接口與類(lèi)繼承各有自己存在的原因,有自己的適用場(chǎng)合,有區別也有一定的聯(lián)系,可以根據自己的具體需求來(lái)選擇。
繼承代價(jià)太大,強制你把父類(lèi)的所有東西都拿過(guò)來(lái),不然就不準使用,這種將方法和屬性強耦合的方式容易導致類(lèi)繼承多了到后面積重難返。使用鴨子類(lèi)型(接口)能避免一部分繼承的缺陷,go里甚至直接繼承都沒(méi)有了,只有接口。
以前我們把物體抽象,大象抽象是動(dòng)物,動(dòng)物抽象是生物,這樣本身就把對象的內容和行為綁定了,比如大象會(huì )噴水,就給大象加個(gè)噴水的方法,但是如果魚(yú)也會(huì )噴水,噴水這個(gè)方法又不能放到動(dòng)物類(lèi)里,那么基于大象和魚(yú)的噴水方法實(shí)現的上層方法就無(wú)法復用,這兩個(gè)噴水在編譯器看來(lái)是沒(méi)有任何關(guān)系的。
開(kāi)始人們想到搞一個(gè)噴水動(dòng)物類(lèi),繼承動(dòng)物類(lèi),大象和魚(yú)再繼承噴水動(dòng)物類(lèi)。但是這樣終究治標不治本,再有其他的變化,繼承鏈又要修改。
因為實(shí)際上我們使用對象,都是在使用其方法(屬性其實(shí)也應該算方法)。
我對面向對象程序過(guò)程的理解,這個(gè)過(guò)程實(shí)際上就是讓對象之間使用方法互發(fā)消息進(jìn)行通信和動(dòng)作,最終完成工作。
大家都知道的一句話(huà),上層應該依賴(lài)抽象而不是依賴(lài)細節,然而依賴(lài)一個(gè)基類(lèi),本身已經(jīng)依賴(lài)這個(gè)基類(lèi)的實(shí)現細節,基類(lèi)要求有個(gè)int成員,那么任何子類(lèi)無(wú)論如何都需要有個(gè)int成員。那么理應將方法抽象出來(lái),而不去關(guān)心其到底是什么,因為我們并不使用對象內部的內容,我們只使用方法。
比如有個(gè)iwriteable接口,表示對象可以按字節寫(xiě)入,那么上層的代碼就不用管寫(xiě)的到底是什么了,只要能寫(xiě)就行,就可以基于這個(gè)iwriteable接口里的方法,寫(xiě)出例如寫(xiě)字符串,寫(xiě)圖片等方法。任何實(shí)現了這個(gè)接口的類(lèi),都可以復用這些寫(xiě)字符串,寫(xiě)圖片的代碼。
那么就有人要問(wèn)了,那如果我確實(shí)要求要有個(gè)int成員,因為我上層代碼要使用呢?那么根據前面說(shuō)的,屬性也是方法,你應該再定義一個(gè)接口,比如這個(gè)int存的是年齡,那么就來(lái)個(gè)haveage接口并實(shí)現它。調用的地方可以要求對象實(shí)現哪幾個(gè)接口,這樣也能獲取需要的屬性。
這么一來(lái),連屬性都沒(méi)有了,那么繼承也可以沒(méi)有了,畢竟你要求的不是基類(lèi)了,是一個(gè)或多個(gè)接口的組合了,所以你可以看到,接口替代繼承是很自然的,而不是什么刻意而為的,是更高級抽象的體現。事實(shí)上基于自然規則的那套大象是動(dòng)物,動(dòng)物是生物的那套面向對象規則,在程序設計里并不好用。所以如果讓我介紹面向對象,我不會(huì )講這些例子。
這個(gè)問(wèn)題很有意思。雖然有一些場(chǎng)景,使用繼承和接口都可以實(shí)現,但是接口的存在絕對不僅僅是代替類(lèi)的繼承。
首先繼承和接口的區別很明顯,用通俗的話(huà)來(lái)講,接口好比一個(gè)人的老師,會(huì )告訴你要做什么(實(shí)現接口要實(shí)現接口中的方法),而繼承就好比是親爹,會(huì )把所有的都給你(子類(lèi)可以調用父類(lèi)提供的方法),一個(gè)人可以有多個(gè)老師,但是只有一個(gè)親爹(接口可以實(shí)現多個(gè),類(lèi)只可以繼承一個(gè))。
那么再來(lái)說(shuō)說(shuō)接口存在的意義。簡(jiǎn)單的理解在Java中接口相當于是定義了規范,而這些規范可以嚴格控制每個(gè)實(shí)現的功能。最明顯的應用就是JavaEE,JavaEE中只定義了各種接口,并沒(méi)有實(shí)現,而我們平時(shí)所使用的基本都是一些實(shí)現了這些接口的第三方類(lèi),比如tomcat的。
另外接口的存在也使得應用的可維護性和擴展性變得更強,比如,在一個(gè)應用中使用了MySQL數據庫,然后未來(lái)某一時(shí)間想要更換成其他數據庫,那么就只需要學(xué)一個(gè)其他數據庫的類(lèi)實(shí)現數據庫接口就可以無(wú)縫切換了。
此外還有一個(gè)很重要的點(diǎn),接口是Java程序中解耦的重要手段。相反的類(lèi)的繼承是確實(shí)增加了耦合度。
所以說(shuō),Java中接口的存在是很有必要的。