Java中的接口以及常見的Cloneable接口用法
1. 概念
接口在 Java 中是一個抽象類型,是抽象方法的集合,是抽象類的更進(jìn)一步。
接口通常以 Interface 來聲明。
一個類通過繼承接口的方式,從而來繼承接口的抽象方法。
2. 語法規(guī)則
在打印圖形的示例中,父類中沒有 Shape 沒有包含別的非抽象方法,所以也可以將它設(shè)計成一個接口。
interface IShape { void draw(); } class Cycle implements IShape { @Override public void draw() { System.out.println("○"); } } public class Test { public static void main(String[] args) { IShape shape = new Rect(); shape.draw(); } }
接口并不是類,編寫接口的方式和類很相似,但是它們屬于不同的概念。
類描述對象的屬性和方法。接口則包含類要實(shí)現(xiàn)的方法。
接口中只能包含抽象方法。對于字段來說, 接口中只能包含靜態(tài)常量(final static)。
interface IShape { void draw(); public static final int num = 10; }
小結(jié):
- 使用 interface 定義一個接口.
- 子類使用 implements 實(shí)現(xiàn)接口,子類可以同時實(shí)現(xiàn)多個接口 implements 多個接口。
- 接口中的方法一定是抽象方法, 因此可以省略 abstract.
- 接口中的方法一定是 public, 因此可以省略 public.
- Cycle 使用 implements 繼承接口,此時表達(dá)的含義不再是 "擴(kuò)展", 而是 "實(shí)現(xiàn)",擴(kuò)展指的是當(dāng)前已經(jīng)有一定的功能了, 進(jìn)一步擴(kuò)充功能。實(shí)現(xiàn)指的是當(dāng)前啥都沒有, 需要從頭構(gòu)造出來。
- 接口無法被實(shí)例化,但是可以被實(shí)現(xiàn)。一個實(shí)現(xiàn)接口的類,必須實(shí)現(xiàn)接口內(nèi)所描述的所有方法,否則就必須聲明為抽象類。
- 一個類如果同時繼承抽象類,實(shí)現(xiàn)接口,請先 extends 一個類,而后 implements 多個接口。
- Java 中允許同時實(shí)現(xiàn)多個接口,不允許多繼承。
3. 接口的命名規(guī)則
- 我們創(chuàng)建接口的時候, 接口的命名一般以大寫字母 I 開頭。
- 接口的命名一般使用 "形容詞" 詞性的單詞。
- 阿里編碼規(guī)范中約定, 接口中的方法和屬性不要加任何修飾符號, 保持代碼的簡潔性。
4. 實(shí)現(xiàn)多個接口
有時候我們需要一個類繼承多個父類,但是在 Java 中只支持單繼承,所以這時候就可以用多接口實(shí)現(xiàn)這種多繼承的效果。
例子:
先通過類表示一組動物:
public class Animal { protected String name; // 有參構(gòu)造方法 public Animal(String name) { this.name = name; } }
動物都有不同的技能,比如說會飛,會游泳,會跑,要想讓不同的動物具有各自不同的特點(diǎn),可以將各種不同的技能設(shè)置成接口。
這樣也方便多種技能的動物“實(shí)現(xiàn)”多個技能。
public interface IFlying { void fly(); }
public interface IRunning { void running(); }
public interface ISwimming { void swimming(); }
接下來就是設(shè)計幾種不同的動物:
首先是??,貓會跑,可以實(shí)現(xiàn)跑的接口方法。
public class Cat extends Animal implements IRunning { public Cat(String name) { super(name); } @Override public void running() { System.out.println(this.name + "正在跑"); } }
還有魚,魚可以游泳。
青蛙,青蛙既可以在陸地上跑跳,也可以在水中游泳,所以這個類可以實(shí)現(xiàn)兩個接口。
public class Frog extends Animal implements ISwimming, IRunning { public Frog(String name) { super(name); } @Override public void running() { System.out.println(this.name + "正在跳"); } @Override public void swimming() { System.out.println(this.name + "正在游泳"); } }
有了接口后,類的調(diào)用者就不必關(guān)注具體類型,而只關(guān)注某個類具備的能力。
在 walk 方法內(nèi)部,不必關(guān)注到底是哪種動物,只要關(guān)注他是否具有跑這個功能就行。其他方法也是如此。
// 多接口 public class TestAniaml { public static void main(String[] args) { Cat cat = new Cat("貓貓"); Frog frog = new Frog("青蛙"); Fish fish = new Fish("小魚"); walk(frog); walk(cat); swim(frog); swim(fish); } public static void walk(IRunning running) { running.running(); } public static void swim(ISwimming swimming) { swimming.swimming(); } }
5. 接口實(shí)現(xiàn)示例
給對象數(shù)組排序
在Arrays工具類中,sort 函數(shù)可以對普通數(shù)組進(jìn)行排序,但是在如下代碼中,如果使用 sort 方法進(jìn)行排序,就會運(yùn)行出錯,拋出異常。
錯誤:
import java.util.Arrays; /** * 接口示例,對學(xué)生對象數(shù)組進(jìn)行排序 */ public class Student implements Comparable<Student> { private String name; private int score; public Student(String name, int score) { this.name = name; this.score = score; } @Override public String toString() { return "Student{" + this.name + '\'' + ", score=" + this.score + '}'; } public static void main(String[] args) { Student[] students = new Student[]{ new Student("小王", 87), new Student("小趙", 90), new Student("小敏", 89), }; Arrays.sort(students); System.out.println(Arrays.toString(students)); } }
從報錯信息以及源碼上來看,可以發(fā)現(xiàn)所有使用 sort (Object[ ] a)方法進(jìn)行排序的對象都必須實(shí)現(xiàn)Comparable接口。
而源碼中的比較類型是 int 類型,所以如果我們想要使用 sort 方法,就要先復(fù)寫Comparable接口中的 compareTo 方法,傳入想要比較的對象類型,也就是 Student 類。
然后就可以實(shí)現(xiàn) sort 方法,運(yùn)行結(jié)果成為按照 score 的大小排序的數(shù)組:
6. Cloneable 接口和深、淺拷貝
6.1 Cloneable 接口
Cloneable 是 Java 中內(nèi)置的接口之一。
使用場景:Object 類中存在一個 clone 方法, 調(diào)用這個方法可以創(chuàng)建一個對象的 "拷貝"。
但是要想合法調(diào)用 clone 方法, 必須要先實(shí)現(xiàn) Cloneable 接口, 否則就會拋出 CloneNotSupportedException 異常。
/** * Cloneable 接口 */ public class B implements Cloneable{ @Override protected B clone() throws CloneNotSupportedException { return (B)super.clone(); } public static void main(String[] args) throws CloneNotSupportedException { B b = new B(); B b1 = b.clone(); B b2 = b; System.out.println(b == b1); System.out.println(b == b2); } }
運(yùn)行結(jié)果:
從結(jié)果可以看出 B 類已經(jīng)具有了拷貝能力,== 看得是兩個對象引用的地址是否是同一個,b 和 b2 還是一個對象只是有兩個名字所以結(jié)果是 true,而 b 經(jīng)過拷貝創(chuàng)新創(chuàng)建了一個新對象 b1,引用指向的地址自然不是一個,結(jié)果就是 false。
拷貝分為淺拷貝和深拷貝,要注意它們的區(qū)別。
6.2 淺拷貝
可以從運(yùn)行結(jié)果看出,改變了拷貝的值,隨之原對象的值也發(fā)生了變化;同樣的改變原對象的值,拷貝后的對象的值也發(fā)生了變化。 這是因?yàn)殡m然 b1 和 b 是兩個不同的對象,但他們內(nèi)部包含的 a 對象卻是相同的。開始時 a 的默認(rèn)值都是0,將100賦給 b1 中的 a 時,b 中的 a 也就改變了,因?yàn)檫@兩個對象中的 a 是同一個引用。
小結(jié):淺拷貝就是當(dāng)一個對象是通過另一個對象 clone 出來的,此時這兩個對象雖然是獨(dú)立的兩個對象,但是這兩個對象的內(nèi)部包含的其他引用是相同的。
6.3 深拷貝
深拷貝就是當(dāng)一個對象是通過另一個對象 clone 出來的,此時這兩個對象是獨(dú)立的兩個對象,這兩個對象所包含的所有其他引用也是獨(dú)立的。
深拷貝的實(shí)現(xiàn)方式:
1. 嵌套實(shí)現(xiàn) clone 方法
2. 序列化實(shí)現(xiàn) clone 方法
現(xiàn)在開發(fā)中常見的序列化就是將一個對象轉(zhuǎn)化成字符串( json),后續(xù)學(xué)習(xí) Java web 時會用到。
總結(jié)
以上為個人經(jīng)驗(yàn),希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Java實(shí)現(xiàn)Dijkstra輸出最短路徑的實(shí)例
這篇文章主要介紹了Java實(shí)現(xiàn)Dijkstra輸出最短路徑的實(shí)例的相關(guān)資料,希望通過本文能幫助到大家,需要的朋友可以參考下2017-09-09Java 發(fā)送http請求(get、post)的示例
這篇文章主要介紹了Java 發(fā)送http請求的示例,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下2020-10-10java CompletableFuture實(shí)現(xiàn)異步編排詳解
這篇文章主要為大家介紹了java CompletableFuture實(shí)現(xiàn)異步編排詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01SpringBoot實(shí)現(xiàn)文件下載的限速功能
在SpringBoot項(xiàng)目中,實(shí)現(xiàn)文件下載的限速功能可以有效控制服務(wù)器帶寬的占用,并防止單個用戶消耗過多的資源,本文將通過具體的代碼示例和詳細(xì)的流程解釋,介紹如何在SpringBoot項(xiàng)目中實(shí)現(xiàn)文件下載的限速功能,需要的朋友可以參考下2024-07-07JavaWeb三大組件之監(jiān)聽器Listener詳解
這篇文章主要介紹了JavaWeb三大組件之監(jiān)聽器Listener詳解,在JavaWeb應(yīng)用程序中,Listener監(jiān)聽器是一種機(jī)制,用于監(jiān)聽和響應(yīng)特定的事件,它可以感知并響應(yīng)與應(yīng)用程序相關(guān)的事件,從而執(zhí)行相應(yīng)的邏輯處理,需要的朋友可以參考下2023-10-10java中實(shí)現(xiàn)一個定時任務(wù)的方式
本文介紹了三種在Java中實(shí)現(xiàn)定時任務(wù)的方法,并推薦使用Spring Boot注解方式,介紹了如何使用`@Scheduled`注解結(jié)合Cron表達(dá)式來設(shè)置定時任務(wù),并提供了一個示例配置文件2025-03-03