<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
在 Dart 中 介面 定義並沒有對應的關鍵字。可能有些人覺得 Dart 中弱化了 介面 的概念,其實不然。我們一般對介面的理解是:介面是更高階別的抽象,介面中的方法都是 抽象方法 ,沒有方法體。通過介面的定義,我們可以通過定義介面來宣告功能,通過實現介面來確保某類擁有這些功能。
不過你有沒有仔細想過,為什麼介面會存在,引入介面的概念是為了解決什麼問題?可能有人會說,通過介面,可以規範一類事物的功能,可以面向介面進行操作,從而可以更加靈活地進行拓展。其實這只是介面的作用,而且這些功能 抽象類 也可以支援。所以介面一定存在什麼特殊的功能,是抽象類無法做到的。
都是抽象方法的抽象類,和介面有什麼本質的區別呢?在我的初入程式設計時,這個問題就伴隨著我,但漸漸地,這個問題好像對程式設計沒有什麼影響,也就被遺忘了。網上很多文章介紹 抽象類 和 介面 的區別,只是在說些無關痛癢的形式區別,並不能讓我覺得介面存在有什麼必要性。
思考一件事物存在的本質意義,可以從沒有這個事物會產生什麼後果來分析。現在想一下,如果沒有介面,一切的抽象行為僅靠 抽象類 完成會有什麼侷限性 或說 弊端。沒有介面,就沒有 實現 (implements) 的概念,其實這就等價於在問 implements 消失了,對程式設計有什麼影響。沒有實現,類之間就只能通過 繼承 (extends) 來維護 is-a 的關係。所以就等價於在問 extends 有什麼侷限性 或說 弊端。答案呼之欲出:多繼承的二義性 。
那問題來了,為什麼類不能支援 多繼承 ,而介面可以支援 多實現 ,繼承 和 實現 有什麼本質的區別呢?為什麼 實現 不會帶來 二義性 的問題,這是理解介面存在關鍵。
下面我們來探討一下 繼承 和 實現 的本質區別。如下 A 和 B 類,有一個相同的成員變數和成員方法:
class A{ String name; A(this.name); void run(){ print("B"); } } class B{ String name; B(this.name); void run(){ print("B"); } }
對於繼承而言 派生類 會擁有基礎類別的成員變數與成員方法,如果支援多繼承,就會出現兩個問題:
class C extends A , B { C(String name) : super(name); // 如果多繼承,該為哪個基礎類別的 name 成員賦值 ?? } void main(){ C c = C("hello") c.run(); // 如果多繼承,該執行哪個基礎類別的 run 方法 ?? }
其實仔細思考一下,一般意義上的介面之所以能夠 多實現 ,就是通過限制,對這兩個問題進行解決。比如 Java 中:
abstract class A{ void run(); } abstract class B{ void run(); } class C implements A,B{ @override void run() { print("C"); } }
到這裡,我們就認識到了為什麼介面不存在 多實現 的二義性問題。這就是 繼承 和 實現 最本質的區別,也是 抽象類 和 介面 最重要的差異。從這裡可以看出,介面就是為了解決多繼承二義性的問題,而引入的概念,這就是它存在的意義。
Dart 中並不像 Java 那樣,有明確的關鍵字作為 介面類 的標識。因為 Dart 中的介面概念不再是 傳統意義 上的狹義介面。而是 Dart 中的任何類都可以作為介面,包括普通的類,這也是為什麼 Dart 不提供關鍵字來表示介面的原因。
既然普通類可以作為介面,那多實現中的 二義性問題 是必須要解決的,Dart 中是如何處理的呢? 如下是 A 、B 兩個普通類,其中有兩個同名 run 方法:
class A{ void run(){ print("run in a"); } } class B{ void run(){ print("run in a"); } void log(){ print("log in a"); } }
當 C 類實現 A 、B 介面,必須強制覆寫 所有 成員方法 ,這點解決了二義性的 問題二 :
那 問題一 中的 成員變數 的歧義如何解決呢?如下,在 A 、B 中新增同名的成員變數:
class A{ final String name; A(this.name); // 略同... } class B{ final String name; B(this.name); // 略同... }
當 C 類實現 A 、B 介面,必須強制覆為 所有 成員變數提供 get 方法 ,這點解決了二義性的 問題一 :
這樣,C 就可以實現兩個普通類,而避免了二義性問題:
class C implements A, B { @override String get name => "C"; @override void log() {} @override void run() {} }
其實,這是 Dart 對 implements 關鍵字的功能加強,迫使派生類必須提供 所有 成員變數的 get 方法,必須覆寫 所有 成員方法。這樣就可以讓 類 和 介面 成為兩個獨立的概念,一個 class 既可以是類,也可以是介面,具有雙重身份。
其區別在於,在 extend 關鍵字後,表示繼承,是作為類來對待;
在 implements 關鍵字之後,表示實現,是作為介面來對待。
我們知道,抽象類中允許定義 普通成員變數/方法 。下面舉個小例子說明一下 繼承 extend 和 實現 implements 的區別。對於繼承來說,派生類只需要實現抽象方法即可,抽象基礎類別 中的普通成員方法可以不覆寫:
而前面說過,implements 關鍵字要求派生類必須覆寫 介面 中的 所有 方法 。也就表示下面的 C implements A 時,也必須覆寫 log 方法。從這個例子中,可以很清楚地看出 繼承 和 實現 的差異性。
抽象類 和 介面 的區別,就是 繼承 和 實現 的區別,在程式碼上的體現是 extend 和 implements 關鍵字功能的區別。只有理解 繼承 的侷限性,才能認清 介面 存在的必要性。
以上就是Flutter 語法進階抽象類和介面本質區別詳解的詳細內容,更多關於Flutter 語法抽象類介面的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45