站長資訊網
最全最豐富的資訊網站

帶你搞懂Java的接口(實例詳解)

本篇文章給大家帶來了關于java的相關知識,其中主要介紹了關于接口的相關問題,包括了接口的概念以及一些知識點匯總、語法規則、接口的使用以及接口的特性等等,下面一起來看一下,希望對大家有幫助。

帶你搞懂Java的接口(實例詳解)

推薦學習:《java視頻教程》

接口

一圖流
帶你搞懂Java的接口(實例詳解)

接口的概念以及一些知識點匯總

接口(英文:Interface),在JAVA編程語言中是一個抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個類通過繼承接口的方式,從而來繼承接口的抽象方法。
接口并不是類,編寫接口的方式和類很相似,但是它們屬于不同的概念。類描述對象的屬性和方法。接口則包含類要實現的方法
除非實現接口的類是抽象類,否則該類要定義接口中的所有方法
接口無法被實例化,但是可以被實現。一個實現接口的類,必須實現接口內所描述的所有方法,否則就必須聲明為抽象類。另外,在 Java 中,接口類型可用來聲明一個變量,他們可以成為一個空指針,或是被綁定在一個以此接口實現的對象。

接口與類的相同處

  • 一個接口中可以有多個
  • 接口文件保存在.Java結尾的文件中,文件名使用接口名
  • 接口的字節碼文件保存在.class結尾的文件中
  • 接口相應的字節碼文件必須在與包名稱相匹配的目錄結構中

接口與類的不同處

  • 接口不能用于實例化對象
  • 接口沒有構造方法
  • 接口中所有的方法必須是抽象方法,在Java8之后接口中可以使用default關鍵字修飾的非抽象方法
  • 接口不能包含成員變量,除了static和final變量
  • 接口被類繼承這個概念不準確,準確來說應該是要被類實現
  • 接口可以實現我們所說的多繼承

接口的一些特點

  • 接口中每一個方法也是隱式抽象的,所以接口中的方法會被隱式得指定為public abstract (只可以是public abstract,其他修飾符都會報錯)
  • 接口中含有變量,但是接口中得變量會被隱式的指定為public static final 變量(并且只能是public,用private修飾會報編譯錯誤)
  • 接口中的方法是不能在接口中實現的,只能由實現接口的類來實現接口中的方法

抽象類和接口的區別

在JDK1.8以前,它們有如下區別

  • 抽象類中的方法可以有具體可執行的語句,即方法體,就是能實現方法的具體功能,但是接口中的方法就不行(比如:System.out.println(“I’m super corn!!”);
  • 抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是public static final類型的
  • 接口中不能含有靜態代碼塊以及靜態方法的使用(用static修飾的方法),而抽象類可以有靜態代碼塊和靜態方法
  • 一個類只能繼承一個抽象類,而一個類卻可以實現多個接口

那么這里要注意的是:
JDK1.8以后,接口中允許含有靜態方法和方法體,允許包含具體實現的方法,該方法我們稱之為“默認方法”,這種方法使用default關鍵字來修飾
JDK1.9以后,允許將方法定義為private,使某些復用的代碼不會將方法暴露出去
抽象類存在的意義是為了讓編譯器更好地校驗,一般抽象類我們不會直接使用,而是使用它的子類,如果不小心通過抽象類創建了對象,編譯器就會及時提醒我們。

注意:以上內容大致瀏覽一遍即可,看不懂沒關系,下面我將為你一一講解,然后回頭再來看這些知識點將會有一種大夢初醒的感覺


那么在現實生活中,接口是什么呢?它可以是筆記本上的USB口,電源插座等
帶你搞懂Java的接口(實例詳解)
帶你搞懂Java的接口(實例詳解)
那么這些接口在實現意義上以及使用標準上也有所不同

  • 電腦的USB口上,可以插:U盤、鼠標、鍵盤…所有符合USB協議的設備
  • 電源插座插孔上,可以插:電腦、電視機、電飯煲…所有符合規范的設備

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

語法規則

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

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

提示:

  1. 創建接口時,接口的命名一般以大寫字母I(讀ai)開頭
  2. 接口的命名一般使用形容詞詞性的單詞
  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{     @Override     public void openDevice(){         System.out.println("打開鼠標");     }          @Override     public void closeDevice(){         System.out.println("關閉鼠標");     }     public void click(){         System.out.println("鼠標點擊");     }}//鍵盤類,實現USB接口public class KeyBoard implements USB {     @Override     public void openDevice(){         System.out.println("打開鍵盤");     }          @Override     public 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();     }}

輸出:
帶你搞懂Java的接口(實例詳解)

instanceof

上面的代碼示例中,提到了instanceof,可能有小伙伴不太理解,我在前面的博客中有介紹,這里再重新為大家講解一下
instanceof是Java的一個保留關鍵字,左邊為對象,右邊為類,返回類型是Boolean類型。
它的具體作用是測試左邊的對象是否是右邊類或者右邊類的子類創建的實例化對象
如果是,則返回true,否則返回false
【instanceof使用注意事項】
現有繼承關系,再有instanceof的使用(包括接口的實現)

【instanceof應用場景】
需要用到對象的強制類型轉換時,需要使用instanceof進行判斷

接口的特性

  1. 接口類型是一種引用類型,但是不能直接new接口的對象
public class TestUSB {     public static void main(String[] args){         USB usb = new USB();     }}//編譯會出錯:USB是抽象的,無法實例化

帶你搞懂Java的接口(實例詳解)

  1. 接口中每一個方法都是public的抽象方法,即接口中的方法會被隱式地指定為public abstract(只能是public abstract,其他修飾符都會報錯)
public interface USB {     //編譯出錯:此處不允許使用修飾符private     //或者是java: 缺少方法主體, 或聲明抽象     private void openDevice();     void closeDevice();     //不同JDK版本編譯器的標準是不一樣的,報錯也是不一樣的}
  1. 接口中的方法是不能在接口中實現的,只能由實現接口的類來實現
public interface USB {     void openDevice();          //編譯失敗:因為接口中的方法默認為抽象方法     //Error:接口抽象方法不能帶有主體}

帶你搞懂Java的接口(實例詳解)
但這里如果我們加上一個default,那么就可以實現方法體了。
帶你搞懂Java的接口(實例詳解)

  1. 重寫接口中的方法時,不能使用default作為訪問權限修飾
public interface USB {void openDevice();//默認為publicvoid closeDevice();//默認為public}public class Mouse implements USB {     @Override     void openDevice(){         System.out.println("打開鼠標");     }          //...}//這里編譯會報錯,重寫USB中的openDevice方法時,不能使用默認修飾符

帶你搞懂Java的接口(實例詳解)
實現這個接口,重寫這個接口的方法的訪問限定修飾符范圍要比接口中的更大

  1. 接口中可以含有變量,但是接口中的變量會被編譯器自動隱式指定為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);         //可以直接通過接口名訪問,說明變量時靜態的                  //下面寫法會報錯 Java:無法為最終變量brand分配值         USB.brand = 2.0;         //說明brand具有final屬性     }}

帶你搞懂Java的接口(實例詳解)

  1. 接口中不能有靜態代碼塊和構造方法
public interface USB {     public USB(){          }//編譯失敗          {          }//編譯失敗          void openDevice();     void closeDevice();}

帶你搞懂Java的接口(實例詳解)

  1. 接口雖然不是類,但是接口編譯完成之后的字節碼文件的后綴格式也是.class
  2. 如果類沒有實現接口中的所有抽象方法,則類必須設置為抽象類
  3. JDK8中規定了接口中可以包含上面所說的default方法

實現多個接口

在Java中,類和類之間是單繼承的,一個類只能由一個父類,即Java中不支持多繼承,但是一個類可以實現多個接口。下面用代碼來演示

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

然后我們再寫一組接口,分別來表示“會飛的”“會跑的”“會游泳的”.

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

帶你搞懂Java的接口(實例詳解)
那么接下來我們創建幾個具體的動物類來接受并實現這些接口
比如,貓會跑

public class Cat extends Animal implements IRunning{     public Cat(String name) {         super(name);     }          @Override     public void run() {         System.out.println("小貓"+this.name+"正在跑");     }}

魚會游泳

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

而青蛙即會跑又會游泳

public class Frog extends Animal implements IRunning,ISwimming{     public Frog(String name){         super(name);     }          @Override     public void run() {         System.out.println("青蛙"+this.name+"正在跑");     }      @Override     public void swim() {         System.out.println("青蛙"+this.name+"正在游泳");     }}

注意:一個類實現多個接口的時候,每個接口中的抽象方法都要去實現,除非類用abstract修飾,為抽象類

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

還有一種動物水陸空三棲,它是大白鵝

public class Goose extends Animal implements IRunning,ISwimming,IFlying{     public Goose(String name) {         super(name);     }      @Override     public void fly() {         System.out.println(this.name+"正在飛");     }      @Override     public void run() {         System.out.println(this.name+"正在跑");     }      @Override     public void swim() {         System.out.println(this.name+"正在漂在水上");     }}

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

貓是一種動物,具有會跑的特性
青蛙是一種動物,即能跑也能有用
大白鵝也是一種動物,技能跑,也能游,還能飛

有了接口之后,類的使用者就不需要去關注具體的類的屬性是否符合,而只需要關心某個類是否具有某個特性/功能,如果有,就可以實現對應的接口
那么我們現在實現一個走路的方法

public class TestDemo1 {     public static void walk(IRunning iRunning){         System.out.println("我帶著小伙伴去散步");         iRunning.run();     }      public static void main(String[] args) {         Cat cat = new Cat("小貓");         walk(cat);                  Frog frog = new Frog("小青蛙");         walk(frog);     }}

輸出結果
帶你搞懂Java的接口(實例詳解)
只要是會跑的,帶有跑這個屬性特征的,都可以接受相應的對象

public class Robot implements IRunning{     private String name;     public Robot(String name){         this.name = name;     }     @Override     public void run() {         System.out.println(this.name+"正在用輪子跑");     }      public static void main(String[] args) {         Robot robot = new Robot("機器人");         walk(robot);     }}

帶你搞懂Java的接口(實例詳解)
帶你搞懂Java的接口(實例詳解)
故輸出結果為
帶你搞懂Java的接口(實例詳解)

接口之間的繼承

在Java中,類和類之間是單繼承的,一個類可以實現多個接口,接口與接口之間可以多繼承。
即:用接口可以達到多繼承的目的
接口可以繼承一個接口,達到復用的效果。這里使用extends關鍵字

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

通過接口繼承創建一個新的接口IAmphibious表示“兩棲的”。
創建的Frog類就實現了這個兩棲的接口

接口之間的繼承就相當于把多個接口合并到了一起

接口使用的例子

我們在之前的數組中講解過給數組排序,那么我們該如何給對象數組排序呢?
首先我們定義一個Student的類,然后重寫一下String方法

public class 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{" +                 "name='" + name + ''' +                 ", score=" + score +                 '}';     }}

我們再給定一個學生對象數組,根據這個對象數組中的元素進行排序
這里我們按照分數降序排序

public class 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{" +                 "name='" + name + ''' +                 ", score=" + score +                 '}';     }      public static void main(String[] args) {         Student[] students = new Student[]{                 new Student("A",95),                 new Student("B",96),                  new Student("C",97),                 new Student("D",98),         };     }}

那么按照我們之前的理解,數組中有一個可以供我們使用的sort方法,我們能否直接使用呢?

Arrays.sort(students);System.out.println(students);//運行結果:Exception in thread "main" java.lang.ClassCastException: class ClassArray.Student cannot be cast to class java.lang.Comparable (ClassArray.Student is in unnamed module of loader 'app'; java.lang.Comparable is in module java.base of loader 'bootstrap') 	at java.base/java.util.ComparableTimSort.countRunAndMakeAscending(ComparableTimSort.java:320) 	at java.base/java.util.ComparableTimSort.sort(ComparableTimSort.java:188) 	at java.base/java.util.Arrays.sort(Arrays.java:1041) 	at ClassArray.Student.main(Student.java:36)

帶你搞懂Java的接口(實例詳解)
我們可以看到這里程序報錯了,這里的意思是Student并沒有實現Comparable的接口
那么這里的sort是進行普通數字的比較,大小關系明確,而我們指定的是兩個學生對象的引用變量,這樣的大小關系的指定是錯誤的,我們需要額外去人為規定對象中的比較元素
那么怎么實現呢?

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

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{" +                 "name='" + name + ''' +                 ", score=" + score +                 '}';     }      @Override     public int compareTo(Student o) {         if (this.score>o.score){             return -1;//      如果當前對象應排在參數對象之前,則返回小于0的數字         } else if(this.score<o.score){             return 1;//      如果當前對象應排在參數對象之后,則返回大于0的數字         } else{             return 0;//      如果當前對象和參數對象不分先后,則返回0               }              }}

那么我們在這里重寫了compareTo的方法,自己定義了比較的規則,我們就自己再去寫一個sort的方法,去調用這個compareTo方法,真正意義上實現對 對象數組的排序
我們使用冒泡排序法

    public static void sort(Comparable[] array){//        這里要注意,雖然接口不能實例化對象,//        但是接口類型的引用變量可以指向它的實現類對象//        這里的實現類對象就是實現了這個接口的對象//        例如Comparable[] comparable = new Student[3];//        所以這里的參數就可以用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方法寫好了,我們寫一個main函數來測試一下

    public static void main(String[] args) {         Student[] students = new Student[]{                 new Student("A",95),                 new Student("B",91),                 new Student("C",97),                 new Student("D",95),         };         System.out.println("sort前:"+Arrays.toString(students));         sort(students);         System.out.println("sort后:"+Arrays.toString(students));     }

運行結果

E:developJavajdk-11binjava.exe "-javaagent:E:IDEAIntelliJ IDEA Community Edition 2021.3.2libidea_rt.jar=65257:E:IDEAIntelliJ IDEA Community Edition 2021.3.2bin" -Dfile.encoding=UTF-8 -classpath E:JAVAcodegyljavaInterfaceoutproductionInterface ClassArray.Studentsort前:[Student{name='A', score=95}, Student{name='B', score=91}, Student{name='C', score=97}, Student{name='D', score=95}]sort后:[Student{name='C', score=97}, Student{name='A', score=95}, Student{name='D', score=95}, Student{name='B', score=91}]

那么我們如果想要按照名字排序呢?也是可以的

import java.util.Arrays;import java.util.Comparator;/**  * Created with IntelliJ IDEA.  * Description: Hello,I would appreciate your comments~  * User:Gremmie  * Date: -04-13  * Destination:利用Comparable的接口實現對 對象數組 選擇性排序的功能  */class Student implements Comparable<Student>{     public String name;     public int age;      public Student(String name, int age) {         this.name = name;         this.age = age;     }      @Override     public String toString() {         return "Student{" +                 "name='" + name + ''' +                 ", age=" + age +                 '}';     }      @Override     public int compareTo(Student o) {         return this.name.compareTo(o.name);     }}class AgeComparator implements Comparator<Student> {     @Override     public int compare(Student o1, Student o2) {         return o1.age-o2.age;     }}class NameComparator implements Comparator<Student> {      @Override     public int compare(Student o1, Student o2) {         return o1.name.compareTo(o2.name);     }}public class TestDemo {      public static void main(String[] args) {         Student[] students = new Student[3];         students[0] = new Student("zhangsan",19);         students[1] = new Student("lisi",8);         students[2] = new Student("abc",78);         AgeComparator ageComparator = new AgeComparator();         NameComparator nameComparator = new NameComparator();                           //這里的方法sort是Array里面自帶的,非常方便,         //只需將我們寫好的比較器傳過去就好了         System.out.println("排序前:"+Arrays.toString(students));         Arrays.sort(students,nameComparator);         System.out.println("排序后:"+Arrays.toString(students));         Comparable<Student>[] studentComparable =students;     }      public static void main2(String[] args) {         /*Student students1 = new Student("zhangsan",19);         Student students2 = new Student("abc",78);         if(students2.compareTo(students1) > 0) {             System.out.println("fafaa");         }*/       }     public static void main1(String[] args) {         Student[] students = new Student[3];         students[0] = new Student("zhangsan",19);         students[1] = new Student("lisi",8);         students[2] = new Student("abc",78);         System.out.println("排序前:"+Arrays.toString(students));         Arrays.sort(students);         System.out.println("排序后:"+Arrays.toString(students));     }}

Clonable接口以及深拷貝

其作用如其名,是用來進行克隆的,Clonable是個很有用的接口。
Object類中存在一個clone方法,調用這個方法可以創建出一個對象,實現“拷貝”。
但是我們想要合法調用clone方法,就要先實現Clonable接口,
否則就會拋出CloneNotSupportedException異常

/**  * Created with IntelliJ IDEA.  * Description: Hello,I would appreciate your comments~  * User:Gremmie  * Date: -04-13  * Destination:利用Clonable的接口實現clone方法,克隆含對象的對象  */class Money implements Cloneable{     public double money = 19.9;      @Override     protected Object clone() throws CloneNotSupportedException {         return super.clone();     }}class Person implements Cloneable{     public int id = 1234;     public Money m = new Money();      @Override     public String toString() {         return "Person{" +                 "id='" + id + ''' +                 '}';     }      @Override     protected Object clone() throws CloneNotSupportedException {         Person tmp = (Person) super.clone();         tmp.m = (Money) this.m.clone();         return tmp;         //return super.clone();     }}public class TestDemo {      public static void main(String[] args) {         Object o = new Person();          Object o2 = new Money();       }      public static void main1(String[] args) throws CloneNotSupportedException {         Person person1 = new Person();         Person person2 = (Person)person1.clone();         System.out.println(person1.m.money);         System.out.println(person2.m.money);         System.out.println("=========================");         person2.m.money = 99.99;         System.out.println(person1.m.money);         System.out.println(person2.m.money);     }}

我們如果只是通過clone,那么就只是拷貝了Person的對象,但是Person中的money對象我們并沒有拷貝下來,只是單純拷貝下來一個地址,那么我們在這里就要進行深拷貝,講Money類也接受Clonable接口,這樣在調用clone方法的時候,money也會進行克隆

推薦學習:《java視頻教程》

贊(0)
分享到: 更多 (0)
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
国产伦精品一区二区三区| 亚洲日韩中文字幕一区| 91久久精品国产免费直播| 精品在线免费观看| 日韩精品无码一区二区三区| 精品国产AV一区二区三区| 久久久国产精品亚洲一区| 久久99精品福利久久久| 久久se精品一区二区| av蓝导航精品导航| 91精品在线播放| 精品国产午夜福利在线观看 | 久久久久久一区国产精品| 污污网站国产精品白丝袜| 日韩欧毛片免费视频| 日韩精品无码视频一区二区蜜桃 | 91探花国产综合在线精品| 久久99久久99精品免视看动漫| 亚洲午夜精品久久久久久人妖| 久久精品国产一区二区三区肥胖| 久久精品视频免费看| 久久精品国产亚洲AV麻豆不卡| 久久的精品99精品66| 亚洲国产精品国自产拍电影| 亚洲精品国产免费| 久久综合日韩亚洲精品色| 日韩电影一区二区三区| 亚洲 日韩 色 图网站| 天天爽夜夜爽夜夜爽精品视频| 亚洲国产精品尤物yw在线| 国产精品免费看久久久香蕉 | 国产69精品久久久久APP下载| 自拍偷在线精品自拍偷99| 亚洲精品无码成人片久久不卡 | 日本精品一区二区三区视频| 日韩加勒比一本无码精品| 国产精品va无码二区| 亚洲国产日韩视频观看| 亚洲精品动漫人成3d在线| 91精品国产乱码久久久久久| 国产在vr视频精品观看|