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