Java中的接口以及常見的Cloneable接口用法
1. 概念
接口在 Java 中是一個(gè)抽象類型,是抽象方法的集合,是抽象類的更進(jìn)一步。
接口通常以 Interface 來聲明。
一個(gè)類通過繼承接口的方式,從而來繼承接口的抽象方法。
2. 語法規(guī)則
在打印圖形的示例中,父類中沒有 Shape 沒有包含別的非抽象方法,所以也可以將它設(shè)計(jì)成一個(gè)接口。
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 定義一個(gè)接口.
- 子類使用 implements 實(shí)現(xiàn)接口,子類可以同時(shí)實(shí)現(xiàn)多個(gè)接口 implements 多個(gè)接口。
- 接口中的方法一定是抽象方法, 因此可以省略 abstract.
- 接口中的方法一定是 public, 因此可以省略 public.
- Cycle 使用 implements 繼承接口,此時(shí)表達(dá)的含義不再是 "擴(kuò)展", 而是 "實(shí)現(xiàn)",擴(kuò)展指的是當(dāng)前已經(jīng)有一定的功能了, 進(jìn)一步擴(kuò)充功能。實(shí)現(xiàn)指的是當(dāng)前啥都沒有, 需要從頭構(gòu)造出來。
- 接口無法被實(shí)例化,但是可以被實(shí)現(xiàn)。一個(gè)實(shí)現(xiàn)接口的類,必須實(shí)現(xiàn)接口內(nèi)所描述的所有方法,否則就必須聲明為抽象類。
- 一個(gè)類如果同時(shí)繼承抽象類,實(shí)現(xiàn)接口,請先 extends 一個(gè)類,而后 implements 多個(gè)接口。
- Java 中允許同時(shí)實(shí)現(xiàn)多個(gè)接口,不允許多繼承。
3. 接口的命名規(guī)則
- 我們創(chuàng)建接口的時(shí)候, 接口的命名一般以大寫字母 I 開頭。
- 接口的命名一般使用 "形容詞" 詞性的單詞。
- 阿里編碼規(guī)范中約定, 接口中的方法和屬性不要加任何修飾符號, 保持代碼的簡潔性。
4. 實(shí)現(xiàn)多個(gè)接口
有時(shí)候我們需要一個(gè)類繼承多個(gè)父類,但是在 Java 中只支持單繼承,所以這時(shí)候就可以用多接口實(shí)現(xiàn)這種多繼承的效果。
例子:
先通過類表示一組動物:
public class Animal {
protected String name;
// 有參構(gòu)造方法
public Animal(String name) {
this.name = name;
}
}動物都有不同的技能,比如說會飛,會游泳,會跑,要想讓不同的動物具有各自不同的特點(diǎn),可以將各種不同的技能設(shè)置成接口。
這樣也方便多種技能的動物“實(shí)現(xiàn)”多個(gè)技能。
public interface IFlying {
void fly();
}public interface IRunning {
void running();
}public interface ISwimming {
void swimming();
}接下來就是設(shè)計(jì)幾種不同的動物:
首先是??,貓會跑,可以實(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 + "正在跑");
}
}還有魚,魚可以游泳。
青蛙,青蛙既可以在陸地上跑跳,也可以在水中游泳,所以這個(gè)類可以實(shí)現(xiàn)兩個(gè)接口。
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)注某個(gè)類具備的能力。
在 walk 方法內(nèi)部,不必關(guān)注到底是哪種動物,只要關(guān)注他是否具有跑這個(gè)功能就行。其他方法也是如此。
// 多接口
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)行出錯(cuò),拋出異常。
錯(cuò)誤:
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));
}
}

從報(bào)錯(cuò)信息以及源碼上來看,可以發(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 類中存在一個(gè) clone 方法, 調(diào)用這個(gè)方法可以創(chuàng)建一個(gè)對象的 "拷貝"。
但是要想合法調(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)具有了拷貝能力,== 看得是兩個(gè)對象引用的地址是否是同一個(gè),b 和 b2 還是一個(gè)對象只是有兩個(gè)名字所以結(jié)果是 true,而 b 經(jīng)過拷貝創(chuàng)新創(chuàng)建了一個(gè)新對象 b1,引用指向的地址自然不是一個(gè),結(jié)果就是 false。
拷貝分為淺拷貝和深拷貝,要注意它們的區(qū)別。
6.2 淺拷貝

可以從運(yùn)行結(jié)果看出,改變了拷貝的值,隨之原對象的值也發(fā)生了變化;同樣的改變原對象的值,拷貝后的對象的值也發(fā)生了變化。 這是因?yàn)殡m然 b1 和 b 是兩個(gè)不同的對象,但他們內(nèi)部包含的 a 對象卻是相同的。開始時(shí) a 的默認(rèn)值都是0,將100賦給 b1 中的 a 時(shí),b 中的 a 也就改變了,因?yàn)檫@兩個(gè)對象中的 a 是同一個(gè)引用。
小結(jié):淺拷貝就是當(dāng)一個(gè)對象是通過另一個(gè)對象 clone 出來的,此時(shí)這兩個(gè)對象雖然是獨(dú)立的兩個(gè)對象,但是這兩個(gè)對象的內(nèi)部包含的其他引用是相同的。
6.3 深拷貝
深拷貝就是當(dāng)一個(gè)對象是通過另一個(gè)對象 clone 出來的,此時(shí)這兩個(gè)對象是獨(dú)立的兩個(gè)對象,這兩個(gè)對象所包含的所有其他引用也是獨(dú)立的。
深拷貝的實(shí)現(xiàn)方式:
1. 嵌套實(shí)現(xiàn) clone 方法

2. 序列化實(shí)現(xiàn) clone 方法
現(xiàn)在開發(fā)中常見的序列化就是將一個(gè)對象轉(zhuǎn)化成字符串( json),后續(xù)學(xué)習(xí) Java web 時(shí)會用到。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
微服務(wù)架構(gòu)設(shè)計(jì)RocketMQ進(jìn)階事務(wù)消息原理詳解
這篇文章主要介紹了為大家介紹了微服務(wù)架構(gòu)中RocketMQ進(jìn)階層面事務(wù)消息的原理詳解,有需要的朋友可以借鑒參考下希望能夠有所幫助2021-10-10
SpringBoot項(xiàng)目打包部署到Tomcat的操作流程
在最近一個(gè)項(xiàng)目中,維護(hù)行里一個(gè)年代較為久遠(yuǎn)的單體項(xiàng)目,需要將項(xiàng)目打包放到的tomcat服務(wù)器下運(yùn)行,所以本文就給大家介紹一下SpringBoot項(xiàng)目打包部署到Tomcat的流程步驟,需要的朋友可以參考下2023-08-08
springboot整合swagger3和knife4j的詳細(xì)過程
knife4j的前身是swagger-bootstrap-ui,取名knife4j是希望她能像一把匕首一樣小巧,輕量,并且功能強(qiáng)悍,下面這篇文章主要介紹了springboot整合swagger3和knife4j的詳細(xì)過程,需要的朋友可以參考下2022-11-11
如何通過XML方式配置并實(shí)現(xiàn)Mybatis
這篇文章主要介紹了如何通過XML方式配置并實(shí)現(xiàn)Mybatis,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-11-11
一篇文章帶你搞定SpringBoot不重啟項(xiàng)目實(shí)現(xiàn)修改靜態(tài)資源
這篇文章主要介紹了一篇文章帶你搞定SpringBoot不重啟項(xiàng)目實(shí)現(xiàn)修改靜態(tài)資源,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
SpringBoot實(shí)現(xiàn)海量數(shù)據(jù)高效實(shí)時(shí)搜索功能
我們都知道隨著業(yè)務(wù)系統(tǒng)的發(fā)展和使用,數(shù)據(jù)庫存儲的業(yè)務(wù)數(shù)據(jù)量會越來越大,逐漸成為了業(yè)務(wù)系統(tǒng)的瓶頸,本文給大家介紹了Spring Boot業(yè)務(wù)系統(tǒng)如何實(shí)現(xiàn)海量數(shù)據(jù)高效實(shí)時(shí)搜索,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-10-10

