【JAVA】接口

? ? ? ? 前面我們說了說抽象類相關內容,這篇我們主要聊聊接口相關內容,這部分很重要,大家引起關注。

1. 接口

1.1 接口的概念

????????接口就是公共的行為規范標準,大家在實現時,只要符合規范標準,就可以通用。在Java中,接口可以看成是:多個類的公共規范,是一種引用數據類型。

1.2 語法規則

接口的定義格式與定義類的格式基本相同,將class關鍵字換成 interface 關鍵字,就定義了一個接口。

public interface 接口名稱{// 抽象方法public abstract void method1(); // public abstract 是固定搭配,可以不寫public void method2();abstract void method3();void method4();// 注意:在接口中上述寫法都是抽象方法,跟推薦方式4,代碼更簡潔
}

提示:

  1. 創建接口時, 接口的命名一般以大寫字母 I 開頭.
  2. 接口的命名一般使用 "形容詞" 詞性的單詞.
  3. 阿里編碼規范中約定, 接口中的方法和屬性不要加任何修飾符號, 保持代碼的簡潔性.

1.3 接口使用

接口不能直接使用,必須要有一個"實現類"來"實現"該接口,實現接口中的所有抽象方法。

public class 類名稱 implements 接口名稱{// ...
}

注意:子類和父類之間是extends 繼承關系,類與接口之間是 implements 實現關系。

請實現筆記本電腦使用USB鼠標、USB鍵盤的例子

1. USB接口:包含打開設備、關閉設備功能

2. 筆記本類:包含開機功能、關機功能、使用USB設備功能

3. 鼠標類:實現USB接口,并具備點擊功能

4. 鍵盤類:實現USB接口,并具備輸入功能

// USB接口
public interface USB {void openDevice();void closeDevice();
}// 鼠標類,實現USB接口
public class Mouse implements USB {@Overridepublic void openDevice() {System.out.println("打開鼠標");}@Overridepublic void closeDevice() {System.out.println("關閉鼠標");}public void click(){System.out.println("鼠標點擊");}
}// 鍵盤類,實現USB接口
public class KeyBoard implements USB {@Overridepublic void openDevice() {System.out.println("打開鍵盤");}@Overridepublic void closeDevice() {System.out.println("關閉鍵盤");}public void inPut(){System.out.println("鍵盤輸入");}
} // 筆記本類:使用USB設備
public class Computer {public void powerOn(){System.out.println("打開筆記本電腦");}public void powerOff(){System.out.println("關閉筆記本電腦");}public void useDevice(USB usb){usb.openDevice();if(usb instanceof Mouse){Mouse mouse = (Mouse)usb;mouse.click();}else if(usb instanceof KeyBoard){KeyBoard keyBoard = (KeyBoard)usb;keyBoard.inPut();} usb.closeDevice();}
}// 測試類:
public class TestUSB {public static void main(String[] args) {Computer computer = new Computer();computer.powerOn();// 使用鼠標設備computer.useDevice(new Mouse());// 使用鍵盤設備computer.useDevice(new KeyBoard());computer.powerOff();}
}

1.4 接口特性

1. 接口類型是一種引用類型,但是不能直接new接口的對象

public class TestUSB {public static void main(String[] args) {USB usb = new USB();}
}// Error:(10, 19) java: day20210915.USB是抽象的; 無法實例化

2. 接口中每一個方法都是public的抽象方法, 即接口中的方法會被隱式的指定為 public abstract(只能是public abstract,其他修飾符都會報錯)

public interface USB {// Error:(4, 18) java: 此處不允許使用修飾符privateprivate void openDevice();void closeDevice();
}

3. 接口中的方法是不能在接口中實現的,只能由實現接口的類來實現

public interface USB {void openDevice();// 編譯失敗:因為接口中的方式默認為抽象方法// Error:(5, 23) java: 接口抽象方法不能帶有主體void closeDevice(){System.out.println("關閉USB設備");}
}

4. 重寫接口中方法時,不能使用默認的訪問權限

public interface USB {void openDevice(); // 默認是public的void closeDevice(); // 默認是public的
}public class Mouse implements USB {@Overridevoid openDevice() {System.out.println("打開鼠標");} // ...
}// 編譯報錯,重寫USB中openDevice方法時,不能使用默認修飾符
// 正在嘗試分配更低的訪問權限; 以前為public

5. 接口中可以含有變量,但是接口中的變量會被隱式的指定為 public static final 變量

public interface USB {double brand = 3.0; // 默認被:final public static修飾void openDevice();void closeDevice();
}public class TestUSB {public static void main(String[] args) {System.out.println(USB.brand); // 可以直接通過接口名訪問,說明是靜態的// 編譯報錯:Error:(12, 12) java: 無法為最終變量brand分配值USB.brand = 2.0; // 說明brand具有final屬性}
}

6. 接口中不能有靜態代碼塊和構造方法

public interface USB {// 編譯失敗public USB(){}{} // 編譯失敗void openDevice();void closeDevice();
}

7. 接口雖然不是類,但是接口編譯完成后字節碼文件的后綴格式也是.class

8. 如果類沒有實現接口中的所有的抽象方法,則類必須設置為抽象類

9. jdk8中:接口中還可以包含default方法。

1.5 實現多個接口

????????在Java中,類和類之間是單繼承的,一個類只能有一個父類,即Java中不支持多繼承,但是一個類可以實現多個接口。下面通過類來表示一組動物.

class Animal {protected String name;public Animal(String name) {this.name = name;}
}

另外我們再提供一組接口, 分別表示 "會飛的", "會跑的", "會游泳的".

interface IFlying {void fly();
} interface IRunning {void run();
}interface ISwimming {void swim();
}

接下來我們創建幾個具體的動物

貓, 是會跑的.

class Cat extends Animal implements IRunning {public Cat(String name) {super(name);}@Overridepublic void run() {System.out.println(this.name + "正在用四條腿跑");}
}

魚, 是會游的.

class Fish extends Animal implements ISwimming {public Fish(String name) {super(name);}@Overridepublic void swim() {System.out.println(this.name + "正在用尾巴游泳");}
}

青蛙, 既能跑, 又能游(兩棲動物)
?

class Frog extends Animal implements IRunning, ISwimming {public Frog(String name) {super(name);} @Overridepublic void run() {System.out.println(this.name + "正在往前跳");} @Overridepublic void swim() {System.out.println(this.name + "正在蹬腿游泳");}
}

注意:一個類實現多個接口時,每個接口中的抽象方法都要實現,否則類必須設置為抽象類。

提示, IDEA 中使用 ctrl + i 快速實現接口

還有一種神奇的動物, 水陸空三棲, 叫做 "鴨子"

class Duck extends Animal implements IRunning, ISwimming, IFlying {public Duck(String name) {super(name);}@Overridepublic void fly() {System.out.println(this.name + "正在用翅膀飛");}@Overridepublic void run() {System.out.println(this.name + "正在用兩條腿跑");}@Overridepublic void swim() {System.out.println(this.name + "正在漂在水上");}
}

????????上面的代碼展示了 Java 面向對象編程中最常見的用法: 一個類繼承一個父類, 同時實現多種接口.繼承表達的含義是 is - a 語義, 而接口表達的含義是 具有 xxx 特性 .

貓是一種動物, 具有會跑的特性.

青蛙也是一種動物, 既能跑, 也能游泳

鴨子也是一種動物, 既能跑, 也能游, 還能飛

????????這樣設計有什么好處呢? 時刻牢記多態的好處, 讓程序猿忘記類型. 有了接口之后, 類的使用者就不必關注具體類型,而只關注某個類是否具備某種能力.

例如, 現在實現一個方法, 叫 "散步"

public static void walk(IRunning running) {System.out.println("我帶著伙伴去散步");running.run();
}

在這個 walk 方法內部, 我們并不關注到底是哪種動物, 只要參數是會跑的, 就行

Cat cat = new Cat("小貓");
walk(cat);Frog frog = new Frog("小青蛙");
walk(frog);// 執行結果
我帶著伙伴去散步
小貓正在用四條腿跑
我帶著伙伴去散步
小青蛙正在往前跳

甚至參數可以不是 "動物", 只要會跑!

class Robot implements IRunning {private String name;public Robot(String name) {this.name = name;}@Overridepublic void run() {System.out.println(this.name + "正在用輪子跑");}
}Robot robot = new Robot("機器人");
walk(robot);// 執行結果
機器人正在用輪子跑

1.6 接口間的繼承

在Java中,類和類之間是單繼承的,一個類可以實現多個接口,接口與接口之間可以多繼承。即:用接口可以達到多繼承的目的。

接口可以繼承一個接口, 達到復用的效果. 使用 extends 關鍵字.

interface IRunning {void run();
}interface ISwimming {void swim();
}// 兩棲的動物, 既能跑, 也能游
interface IAmphibious extends IRunning, ISwimming {}class Frog implements IAmphibious {...
}

通過接口繼承創建一個新的接口 IAmphibious 表示 "兩棲的". 此時實現接口創建的 Frog 類, 就繼續要實現 run 方法, 也需要實現 swim 方法.

接口間的繼承相當于把多個接口合并在一起.

1.7 接口使用實例

給對象數組排序

class Student {private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic String toString() {return "[" + this.name + ":" + this.score + "]";}
}

再給定一個學生對象數組, 對這個對象數組中的元素進行排序(按分數降序).

Student[] students = new Student[] {new Student("張三", 95),new Student("李四", 96),new Student("王五", 97),new Student("趙六", 92),
};

按照我們之前的理解, 數組我們有一個現成的 sort 方法, 能否直接使用這個方法呢?

Arrays.sort(students);
System.out.println(Arrays.toString(students));// 運行出錯, 拋出異常.
Exception in thread "main" java.lang.ClassCastException: Student cannot be cast to java.lang.Comparable

仔細思考, 不難發現, 和普通的整數不一樣, 兩個整數是可以直接比較的, 大小關系明確. 而兩個學生對象的大小關系怎么確定? 需要我們額外指定.

讓我們的 Student 類實現 Comparable 接口, 并實現其中的 compareTo 方法

class Student implements Comparable {private String name;private int score;public Student(String name, int score) {this.name = name;this.score = score;}@Overridepublic String toString() {return "[" + this.name + ":" + this.score + "]";} @Overridepublic int compareTo(Object o) {Student s = (Student)o;if (this.score > s.score) {return -1;} else if (this.score < s.score) {return 1;} else {return 0;}}
}

在 sort 方法中會自動調用 compareTo 方法. compareTo 的參數是 Object , 其實傳入的就是 Student 類型的對象.然后比較當前對象和參數對象的大小關系(按分數來算).

  • 如果當前對象應排在參數對象之前, 返回小于 0 的數字;
  • 如果當前對象應排在參數對象之后, 返回大于 0 的數字;
  • 如果當前對象和參數對象不分先后, 返回 0;

再次執行程序, 結果就符合預期了

// 執行結果
[[王五:97], [李四:96], [張三:95], [趙六:92]]

注意事項: 對于 sort 方法來說, 需要傳入的數組的每個對象都是 "可比較" 的, 需要具備 compareTo 這樣的能力. 通過重寫 compareTo 方法的方式, 就可以定義比較規則.

為了進一步加深對接口的理解, 我們可以嘗試自己實現一個 sort 方法來完成剛才的排序過程(使用冒泡排序)

public static void sort(Comparable[] array) {for (int bound = 0; bound < array.length; bound++) {for (int cur = array.length - 1; cur > bound; cur--) {if (array[cur - 1].compareTo(array[cur]) > 0) {// 說明順序不符合要求, 交換兩個變量的位置Comparable tmp = array[cur - 1];array[cur - 1] = array[cur];array[cur] = tmp;}}}
}

再次執行代碼
?

sort(students);
System.out.println(Arrays.toString(students));// 執行結果
[[王五:97], [李四:96], [張三:95], [趙六:92]]

1.8 Clonable 接口和深拷貝

Java 中內置了一些很有用的接口, Clonable 就是其中之一.

Object 類中存在一個 clone 方法, 調用這個方法可以創建一個對象的 "拷貝". 但是要想合法調用 clone 方法, 必須要先實現 Clonable 接口, 否則就會拋出 CloneNotSupportedException 異常.

class Animal implements Cloneable {private String name;@Overridepublic Animal clone() {Animal o = null;try {o = (Animal)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();} return o;}
}public class Test {public static void main(String[] args) {Animal animal = new Animal();Animal animal2 = animal.clone();System.out.println(animal == animal2);}
}// 輸出結果
// false

淺拷貝 VS 深拷貝

Cloneable 拷貝出的對象是一份 "淺拷貝"觀察以下代碼:

class Money {public double m = 99.99;
}class Person implements Cloneable{public Money money = new Money();@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}public class TestDemo3 {public static void main(String[] args) throws CloneNotSupportedException {Person person1 = new Person();Person person2 = (Person) person.clone();System.out.println("通過person2修改前的結果");System.out.println(person1.money.m);System.out.println(person2.money.m);person2.money.m = 13.6;System.out.println("通過person2修改后的結果");System.out.println(person1.money.m);System.out.println(person2.money.m);}
} // 執行結果
通過person2修改前的結果
99.99
99.99
通過person2修改后的結果
13.6
13.6

如上代碼,我們可以看到,通過clone,我們只是拷貝了Person對象。但是Person對象中的Money對象,并沒有拷貝。通過person2這個引用修改了m的值后,person1這個引用訪問m的時候,值也發生了改變。這里就是發生了淺拷貝。

1.9 抽象類和接口的區別

????????抽象類和接口都是 Java 中多態的常見使用方式. 都需要重點掌握. 同時又要認清兩者的區別(重要!!! 常見面試題).

????????核心區別: 抽象類中可以包含普通方法和普通字段, 這樣的普通方法和字段可以被子類直接使用(不必重寫), 而接口中不能包含普通方法, 子類必須重寫所有的抽象方法.

????????如之前寫的 Animal 例子. 此處的 Animal 中包含一個 name 這樣的屬性, 這個屬性在任何子類中都是存在的. 因此此處的 Animal 只能作為一個抽象類, 而不應該成為一個接口.

class Animal {protected String name;public Animal(String name) {this.name = name;}
}

再次提醒:

????????抽象類存在的意義是為了讓編譯器更好的校驗, 像 Animal 這樣的類我們并不會直接使用, 而是使用它的子類.萬一不小心創建了 Animal 的實例, 編譯器會及時提醒我們.

? ? ? ? ?結束啦,這就是接口相關的全部內容,后面計劃說說一個特別的類,大家敬請期待,接口這個部分大家好好琢磨,這是很重要的一個部分。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/16428.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/16428.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/16428.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

力扣 739. 每日溫度 python AC

單調棧 class Solution:def dailyTemperatures(self, temperatures):size len(temperatures)ll []ans [0] * sizefor i in range(size - 1, -1, -1):while ll and temperatures[i] > temperatures[ll[-1]]:ll.pop()if ll:ans[i] ll[-1] - ill.append(i)return ans

C語言 數組——向函數傳遞數組

目錄 把數組傳給函數&#xff08;Passing Arrays to Functions&#xff09; 向函數傳遞一維數組 向函數傳遞二維數組 數組在學生成績管理中的應用 例&#xff1a;計算每個學生的平均分 把數組傳給函數&#xff08;Passing Arrays to Functions&#xff09; 向函數傳遞一維…

gnocchi學習小結

背景 總結gnocchi 4.4版本gnocchi-metricd工作流程 入口 gnocchi.cli.metricd metricd stop after processing metric默認為0&#xff0c;調servicemanager run MetricdServiceManager __init__ 服務邏輯封裝到MetricdServiceManager初始化中 主要由MetricProcessor, Met…

基于Vue的前端自定義詢問彈框與輸入彈框組件的設計與實踐

基于Vue的前端自定義詢問彈框與輸入彈框組件的設計與實踐 摘要 隨著技術的不斷進步&#xff0c;前端開發面臨越來越多的挑戰&#xff0c;其中之一就是如何有效管理復雜的業務邏輯和用戶體驗。傳統的整塊應用開發方式在面對頻繁的功能變更和用戶體驗優化時&#xff0c;往往顯得…

python數據分析-CO2排放分析

導入所需要的package import numpy as np import pandas as pd import matplotlib.pyplot as plt import seaborn as sns import datetime %matplotlib inline plt.rcParams[font.sans-serif] [KaiTi] #中文 plt.rcParams[axes.unicode_minus] False #負號 數據清洗…

MySQL數據表索引命名規范

在數據庫設計和開發過程中&#xff0c;索引是提高查詢性能的重要工具。合理的索引命名規范不僅能提高代碼的可讀性&#xff0c;還能便于維護和管理。本文將詳細介紹MySQL數據表索引的命名規范&#xff0c;包括不同類型索引的命名方法&#xff0c;并提供多個代碼示例以說明如何命…

SSH 遠程登錄系統和遠程拷貝

文章目錄 目錄 文章目錄 前言 一.SSH的基本用法 SSH基本用法&#xff1a; SSH無密碼登錄 二.SSH安全設置 三.SSH限制用戶 前言 很多時候服務器并沒有服務器&#xff0c;我們也不能每次都通過控制臺去管理服務器&#xff0c;這時候就需要遠程登錄&#xff0c;相比于Telnet&a…

京東應屆生公司內網說了一句‘什么時候被pdd收購‘,結果慘遭辭退

京東應屆生公司內網說了一句’什么時候被pdd收購’&#xff0c;結果慘遭公司開除 這個事最近在圈子討論比較多 前二天&#xff0c;有一個上海交大畢業的應屆生&#xff0c;在京東實習了9個月&#xff0c;好不容易轉正12天后&#xff0c;只因在內網說了一句話&#xff0c;就被…

upload-labs 21關解析

目錄 一、代碼審計 二、實踐 三、總結 一、代碼審計 $is_upload false; $msg null; if(!empty($_FILES[upload_file])){//檢查MIME$allow_type array(image/jpeg,image/png,image/gif);if(!in_array($_FILES[upload_file][type],$allow_type)){$msg "禁止上傳該類型…

一個程序員的牢獄生涯(38)答案

星期一 答 案 我被這個不知道什么時候無聲無息的出現在身后的人嚇出了一身的冷汗。 看到我發現了他,這個人慢慢地抬起了頭……“他X的,是小X州!” 此時的小X州臉上并沒有著急等待上廁所的表情,反而是用一種狡黠的眼神看著我。一直充滿的敵意,現在又多了一絲威脅的神情,讓…

Quartus Cyclone I II III IVE 器件型號

玩耍了一個 EP2 型號的開發板&#xff0c;發現 安裝的quartus13 沒有Cyclone II 型號&#xff0c;經過探索發現了是版本不對。 https://www.intel.com/content/www/us/en/software-kit/711920/intel-quartus-ii-subscription-edition-design-software-version-13-0sp1-for-win…

行業分析---造車新勢力之蔚來汽車

1 前言 在之前的博客中&#xff0c;筆者分析了蘋果《行業分析---我眼中的Apple Inc.》&#xff0c;蘋果已經成為世界級的公司。隨后也分析了電動汽車公司特斯拉《行業分析---馬斯克的Tesla》&#xff0c;特斯拉也在不斷成長。目前能分析的新能源汽車公司不多&#xff0c;小米汽…

Minecraft服務器如何搭建

Minecraft這是原版英文名稱&#xff0c;在中國大陸被譯為《我的世界》&#xff0c;這款游戲很火爆。臺灣的很多小伙伴也在玩&#xff0c;其譯名為《我的創世神》。現在這款游戲在國內已經被網易代理了。因為這款游戲開源&#xff0c;所以任何人都可以搭建服務器端&#xff0c;如…

機器人支持回調接口配置(詳細教程)

大家伙&#xff0c;我是雄雄&#xff0c;歡迎關注微信公眾號&#xff1a;雄雄的小課堂。 一、前言 今天&#xff0c;給大家介紹一下&#xff0c;如何在機器人中配置回調地址和接口編寫。很多時候我們可能有這樣的場景&#xff0c;收到消息后&#xff0c;想自己處理一下消息的內…

【Linux】Linux的基本指令_2

文章目錄 二、基本指令8. man9. nano 和 cat10. cp11. mv12. echo 和 > 和 >> 和 <13. more 和 less14. head 和 tail 和 | 未完待續 二、基本指令 8. man Linux的命令有很多參數&#xff0c;我們不可能全記住&#xff0c;我們可以通過查看聯機手冊獲取幫助。訪問…

基于門控的循環神經網絡:GRU

門控循環單元&#xff08;GatedRecurrentUnit&#xff0c;GRU&#xff09;網絡&#xff0c;也是一種基于門控的循環神經網絡&#xff0c;但是名氣不如LSTM大&#xff0c;GRU是對LSTM的一種改版&#xff0c;可以理解為是LSTM的簡化版。LSTM有三個門&#xff0c;輸入門&#xff0…

【C++】牛客 ——DP36 abb

?題目鏈接&#xff1a; DP36 abb ?題目描述 leafee 最近愛上了 abb 型語句&#xff0c;比如“疊詞詞”、“惡心心” leafee 拿到了一個只含有小寫字母的字符串&#xff0c;她想知道有多少個 "abb" 型的子序列&#xff1f; 定義&#xff1a; abb 型字符串滿足以下…

perl:用 Net::Server 創建簡單的流媒體服務器

這是一個使用Perl Net::Server 模塊創建的簡單流媒體服務器示例&#xff0c;它能夠播放.flv文件。 首先&#xff0c;確保安裝了Net::Server模塊&#xff0c;如果沒有安裝&#xff0c;可以使用CPAN來安裝它&#xff1a; 運行 cpan Net::Server RHANDOM/Net-Server-2.014.tar.…

力扣刷題--448. 找到所有數組中消失的數字【簡單】

題目描述 給你一個含 n 個整數的數組 nums &#xff0c;其中 nums[i] 在區間 [1, n] 內。請你找出所有在 [1, n] 范圍內但沒有出現在 nums 中的數字&#xff0c;并以數組的形式返回結果。 示例 1&#xff1a; 輸入&#xff1a;nums [4,3,2,7,8,2,3,1] 輸出&#xff1a;[5,6…

Python零基礎-中【詳細】

接上篇繼續&#xff1a; Python零基礎-上【詳細】-CSDN博客 目錄 十、函數式編程 1、匿名函數lambda表達式 &#xff08;1&#xff09;匿名函數理解 &#xff08;2&#xff09;lambda表達式的基本格式 &#xff08;3&#xff09;lambda表達式的使用場景 &#xff08;4&…