成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

如何理解Java中接口存在的意義

開發 后端
這里我先拋出一個形象的解釋,大家帶著這個解釋結合全文來理解接口存在的意義是什么,一起看一下吧。

 0. 前言

在我自己早期學習編程的時候,對接口存在的意義實在困惑,我自己亂寫代碼的時候基本上不可能意識到需要去寫接口,不知道接口到底有什么用,為什么要定義接口,感覺定義接口只是 提前做了個多余的工作。

這里我先拋出一個形象的解釋,大家帶著這個解釋結合全文來理解接口存在的意義是什么:

我們把電腦主板上的內存插槽,顯卡插槽等類比為接口,為什么在主板上搞這么多插槽呢?多浪費機箱空間啊?直接用電烙鐵把顯卡和內存的引腳一根一根焊到主板上不就得了(手動滑稽)。估計讀到這里大伙兒心里也大概明白了接口的大致作用,焊死了后,如果你焊錯位置了或者拆電腦的時候,就需要使用電烙鐵進行拆裝,多愚蠢哦。

全文脈絡思維導圖如下:

1. 什么是抽象類

在講解接口之前,抽象類是繞不過去的一個概念,接口可以認為是一個比抽象類還要抽象的類。

什么是抽象類?「包含一個或多個抽象方法的類就是抽象類,抽象方法即沒有方法體的方法」,抽象方法和抽象類都必須聲明為 abstract。例如: 

  1. // 抽象類  
  2. public abstract class Person {  
  3.     // 抽象方法  
  4.  public abstract String getDescription();  

切記!「除了抽象方法之外,抽象類還可以包含具體數據和具體方法」。例如, 抽象類 Person 還保存著姓名和一個返回姓名的具體方法: 

  1. public abstract class Person{  
  2.     private String name;  
  3.     public Person(String name){  
  4.      this.name = name ;  
  5.     }  
  6.     public abstract String getDescription();  
  7.     public String getName(){  
  8.      return name;  
  9.     }  

    ❝    許多程序員都會「錯誤」的認為,在抽象類中不能包含具體方法。其實這也是接口和抽象類的不同之處,接口中是不能包含具體方法的。    ❞

「抽象類不能被實例化」。也就是說,如果將一個類聲明為 abstract, 就不能創建這個類的對象。 

  1. new Person("Jack"); // Error 

可以定義一個抽象類的對象變量, 但是它只能引用非抽象子類的對象。假設 Student 類是 Person 的非抽象子類: 

  1. Person p = new Student("Jack"); // Right 

所謂非抽象子類就是說,如果創建一個繼承抽象類的子類并為之創建對象,那么就「必須為父類的所有抽象方法提供方法定義」。如果不這么做(可以選擇不做),子類仍然是一個抽象類,編譯器會強制我們為新類加上 abstract 關鍵字。

下面定義擴展抽象類 Person 的具體子類 Student: 

  1. public class Student extends Person {   
  2.     private String major;   
  3.     public Student(String name, String major) {   
  4.         super(name);   
  5.         this.major = major;   
  6.     }   
  7.     @Override  
  8.     public String getDescription(){ // 實現父類抽象方法  
  9.      return "a student majoring in " + major;   
  10.     }   
  11. }  

在 Student 類中實現了父類中的抽象方法 getDescription 。因此,「在 Student類中的全部方法都是非抽象的, 這個類不再是抽象類」。

調用如下: 

  1. Person p = new Student("Jack","Computer Science");  
  2. p.getDescription(); 

由于不能構造抽象類 Person的對象, 所以變量 p 永遠不會引用 Person 對象, 而是引用諸如 Student這樣的具體子類對象, 而這些對象中都重寫了 getDescription方法。

2. 什么是接口

接口的本質其實也是一個類,而且是一個比抽象類還要抽象的類。怎么說呢?抽象類是能夠包含具體方法的,而接口杜絕了這個可能性,「在 Java 8 之前,接口非常純粹,只能包含抽象方法,也就是沒有方法體的方法」。而 Java 8 中接口出現了些許的變化,開始允許接口包含默認方法和靜態方法,這個下文會講解。

Java 使用關鍵字 interface 而不是 class 來創建接口。和類一樣,通常我們會在關鍵字 interface 前加上 public 關鍵字,否則接口只有包訪問權限,只能在接口相同的包下才能使用它。 

  1. public interface Concept {  
  2.     void idea1();  
  3.     void idea2();  

同樣的,接口中既然存在抽象方法,那么他就需要被擴展(繼承)。使用 implements 關鍵字使一個類擴展某個特定接口(或一組接口),通俗來說:接口只是外形,現在這個擴展子類要說明它是如何工作的。 

  1. class Implementation implements Concept {  
  2.     @Override  
  3.     public void idea1() {  
  4.         System.out.println("idea1");  
  5.     }      
  6.     @Override  
  7.     public void idea2() {  
  8.         System.out.println("idea2");  
  9.     }  

這里需要注意的是,你可以選擇顯式地聲明接口中的方法為 public,但是「即使你不這么做,它們也是 public 的」。所以當實現一個接口時,來自接口中的方法必須被定義為 public。否則,它們只有包訪問權限,這樣在被繼承時,它們的可訪問權限就被降低了,這是 Java 編譯器所不允許的。

另外,接口中是允許出現常量的,與接口中的方法都自動地被設置為 public—樣,「接口中的域將被自動被設置為 public static final 類型」,例如: 

  1. public interface Concept {  
  2.  void idea1(); // public void idea1();  
  3.     // 靜態屬性  
  4.  double item = 95; // a public static final constant  

    ❝    可以將接口方法標記為 public,將域標記為 public static final。有些程序員出于習慣或提高清晰度的考慮, 愿意這樣做。但 Java 語言規范卻「建議不要書寫這些多余的關鍵字」。    ❞

3. 接口的特性

接口和類其中不同的一點就是,我們「無法像類一樣使用 new 運算符來實例化一個接口」: 

  1. x = new Concept(. . .); // ERROR 

原因也很簡單,接口連具體的構造方法都沒有,肯定是無法實例化的。

當然, 盡管不能構造接口的對象,聲明接口的變量還是可以的: 

  1. Concept x; // OK 

接口變量必須引用實現了接口的類對象: 

  1. x = new Implementation(. . .); // OK provided Implementation implements Concept 

接下來, 如同使用 instanceof 檢查一個對象是否屬于某個特定類一樣, 也可以使用 instanceof檢查一個對象是否實現了某個特定的接口: 

  1. if(x instanceof Concept){  
  2.  ...  

另外,與可以建立類的繼承關系一樣,「接口也可以被繼承」: 

  1. public interface Concept1 {  
  2.     void idea1();  
  3.     void idea2();  
  4.  
  5. -------------------------------------------    
  6. public interface Concept2 extends Concept1{  
  7.  double idea3();  

當然,讀到這里大家可能依然無法理解,既然有了抽象類,為什么 Java 程序設計語言還要不辭辛苦地引入接口這個概念?

很重磅!因為「一個類可以實現多個接口,但是一個類只能繼承一個父類」。正是接口的出現打破了 Java 這種單繼承的局限,為定義類的行為提供了極大的靈活性。 

  1. class Implementation implements Concept1, Concept2 // OK 

有一條實際經驗:在合理的范圍內盡可能地抽象。顯然,接口比抽象類還要抽象。因此,一般更傾向使用接口而不是抽象類。

4. Java 8 接口新特性

上文提過一嘴,「在 Java 8 中,允許在接口中增加靜態方法和默認方法」。理論上講,沒有任何理由認為這是不合法的,只是這有違于將接口作為抽象規范的初衷。舉個例子: 

  1. public interface Concept {  
  2.     // 靜態方法  
  3.  public static void get(String name){  
  4.      System.out.println("hello " + name);  
  5.     }  
  6.     // 默認方法  
  7.     default void idea1(){  
  8.         System.out.println("this is idea1");  
  9.     };  

用 default 修飾符標記的方法就是默認方法,這樣子類就不需要去實現這個方法了。

不過,引入默認方法后,就出現了一個「默認方法沖突」的問題。如果先在一個接口 A 中將一個方法 idea 定義為默認方法, 然后又在另一個接口 B 或者超類 C 中定義了同樣的方法  idea,然后類 D 實現了這兩個接口 A 和 B(或超類 C)。于是類 D 中就有了方法 idea 的兩個默認實現,出現了沖突,為此,Java 制定了一套規則來解決這個二義性問題:

1 )  「超類優先」。如果超類提供了一個具體方法,接口中的同名且有相同參數類型的默認方法會被忽略。

2 )  「接口沖突」。如果一個父類接口提供了一個默認方法,另一個父類接口也提供了一個同名而且參數類型相同的方法,子類必須覆蓋這個方法來解決沖突。例如: 

  1. interface A {  
  2.  default void idea(){  
  3.   System.out.println("this is A");  
  4.  }  
  5.  
  6. interface B {  
  7.  default void idea(){  
  8.   System.out.println("this is B");  
  9.  }  
  10.  
  11. // 需要在 D 類中覆蓋 idea 方法  
  12. class D implements A, B{  
  13.     public void getName(){  
  14.      System.out.println("this is D");  
  15.     }  

現在假設 B接口沒有為 idea 提供默認實現: 

  1. interface B {  
  2.  void idea();  

那么 D 類會直接從 A 接口繼承默認方法嗎?這好像挺有道理, 不過,Java 設計者更強調一致性。兩個接口如何沖突并不重要,「只要有一個接口提供了一個默認實現,編譯器就會報告錯誤, 我們就必須解決這個二義性」。

當然,如果兩個接口都沒有為共享方法提供默認實現, 那么就與 Java 8 之前的情況一樣,這里不存在沖突。

5. 接口存在的意義

在我自己早期學習編程的時候,對接口存在的意義實在困惑,我自己亂寫代碼的時候基本上不可能意識到需要去寫接口,不知道接口到底有什么用,為什么要定義接口,感覺定義接口只是提前做了個多余的工作。

其實不是,定義接口并非多余,「接口是用來提供公用的方法,規定子類的行為的」。舉個例子,讓大家直觀的感受下接口的作用:

比如有個網站, 需要保存不同客戶的信息, 有些客戶從 Web 網站來, 有些客戶從手機客戶端來, 有些客戶直接從后臺管理系統錄入。假設不同來源的客戶有不同的處理業務流程, 這個時候我們定義接口來提供一個保存客戶信息的方法,然后不同的平臺實現我們這個保存客戶信息的接口,以后保存客戶信息的話, 我們只需要知道這個接口就可以了,具體調用的方法被封裝成了黑盒子,這也就是 Java 的多態的體現,「接口幫助我們對這些有相同功能的方法做了統一管理」。

再比如說,我們要做一個畫板程序,其中里面有一個面板類,主要負責繪畫功能,然后你就定義了這個類,可是在不久的將來,你突然發現這個類滿足不了你了,然后你又要重新設計這個類,更糟糕是你可能要廢棄這個現有的類,那么其他引用這個類的地方也需要做出修改,顯然這樣非常麻煩。

如果你一開始定義了一個接口,把繪畫功能放在這個接口里,然后定義類時實現這個接口,那么你只需要用這個接口去引用實現它的類就行了,以后要修改的話只不過是引用另一個類而已。「接口的使用提高了代碼的可維護性和可擴展性」。

另外,從這兩個例子我們也能看出,接口不僅「降低了代碼的耦合度」,而且僅僅描敘了程序對外的服務,不涉及任何具體的實現細節,這樣也就比較「安全」一些。 

 

責任編輯:龐桂玉 來源: Hollis
相關推薦

2010-06-21 09:18:26

anacron服務

2021-09-06 08:55:16

軟件開發 架構

2021-10-11 08:58:34

Goroutine操作系統

2010-08-18 10:46:38

DB2 code pa

2015-03-23 09:33:43

Java抽象類Java接口Java

2020-08-23 11:32:21

JavaScript開發技術

2021-11-26 00:05:56

RabbitMQVirtualHostWeb

2021-05-06 09:18:18

SQL自連接數據

2018-06-26 10:39:37

2023-11-28 18:09:49

Java多態

2020-10-13 14:38:50

機器學習數據

2009-04-27 09:41:01

C#WPFTemplate

2012-02-16 10:53:10

Java

2015-11-02 17:20:00

Java弱引用

2021-05-14 06:15:48

SpringAware接口

2024-02-04 09:38:22

云計算應用映射企業

2014-05-15 11:41:32

2018-04-02 13:10:41

2009-04-10 09:43:00

Java輸出流異常

2017-09-23 15:28:32

JavaOptional方法
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 国产乱码久久久久久 | 免费一看一级毛片 | 国内自拍偷拍视频 | 精品亚洲一区二区三区四区五区高 | 中文字幕精品一区久久久久 | 91久久久www播放日本观看 | 超碰人人做 | 奇米久久久 | 国产精品高潮呻吟 | 日本高清精品 | 人人干人人干人人 | 4h影视 | 国产精品一二三区 | 国产欧美精品一区二区 | 国产在线网站 | 伊人久久综合 | 精品一区在线看 | 天天干天天插 | 亚洲网一区| 国产美女精品视频免费观看 | 国产成人艳妇aa视频在线 | 九九热精品在线 | 国产目拍亚洲精品99久久精品 | 国产精久久久 | 激情五月婷婷 | 永久看片| 久久精品网 | 人人鲁人人莫人人爱精品 | 国产日产久久高清欧美一区 | 国产 日韩 欧美 制服 另类 | 青娱乐自拍 | 日韩欧美一区二区三区在线播放 | 在线视频一区二区 | 请别相信他免费喜剧电影在线观看 | 欧美一级视频 | 99热这里都是精品 | 日韩视频在线观看中文字幕 | 亚洲精品一区二区三区丝袜 | 成人啊啊啊 | 欧美区日韩区 | yiren22综合网成人 |