概念
在Java中,接口可以被看成是一種公共規范,是一種引用數據類型。
語法
1.接口的定義格式與類的定義格式基本相同,將class關鍵字替換為interface關鍵字:
public interface IShape {}
2.類與接口之間使用implements關鍵字來實現接口,并且這個類中必須重寫實現接口中的抽象方法
public interface IShape {void draw();
}public class Cycle implements IShape{public void draw(){System.out.println("畫一個圓圈---");}
}
抽象類和接口的區別:
1.抽象類中可以存在普通成員變量和方法,而接口中只能存在常量和抽象方法。
2.抽象類可以有構造方法,接口沒有構造方法。
接口使用
下面是一個簡單的接口實現電腦使用的例子:
public interface USB {void openDevice();void closeDevice();
}public class Mouse implements USB{public void openDevice(){System.out.println("打開鼠標");}public void closeDevice(){System.out.println("關閉鼠標");}public void click(){System.out.println("鼠標點擊");}
}public class KeyBoard implements USB{@Overridepublic void openDevice() {System.out.println("打開鍵盤");}@Overridepublic void closeDevice() {System.out.println("關閉鍵盤");}public void input(){System.out.println("鍵盤打字");}
}public class test {public static void main(String[] args) {Computer computer = new Computer();computer.open();computer.useUsbDevice(new KeyBoard());computer.useUsbDevice(new Mouse());computer.close();}
}
運行結果:
接口特性
1.接口是一種引用類型,但不能直接new接口的對象:
public class TestUSB {public static void main(String[] args) {USB usb = new USB();//編譯報錯}
}
2.在接口中,所有成員方法默認是抽象方法,沒有具體的實現,由public abstrct修飾,即便不寫
public interface IShape {public static final int a=1;public int b=2;static int c=3;final int d=4;int e=5;//這五種形式本質均相同,由public static final 修飾public abstract void fun1();public void fun2();abstract void fun3();void fun4();//這四種形式本質均相同,由public abstract修飾
}
3.接口中的方法不能再接口中實現,必須由實現接口的類來實現:
public interface USB {void openDevice();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方法時,不能使用默認修飾符
}
5.在接口中,所有成員變量默認由public static final 修飾,即便不寫
public interface IShape {public static final int a=1;public int b=2;static int c=3;final int d=4;int e=5;//這五種形式本質均相同,由public static final 修飾
}
6.?在接口中,由default關鍵字和static關鍵字修飾的成員方法可以有具體的實現。
default void fun5(){System.out.println("default方法");}static void fun6(){System.out.println("static方法");}
?7.接口中不能有靜態代碼塊和構造方法。
8.接口雖然不是類,但是接口編譯完成后字節碼文件的后綴格式也是.class
實現多個接口
?在Java中,類和類之間不支持多繼承,一個子類只能有一個父類,但是一個類可以實現多個接口,下面通過類來表示一組動物:
public class Animal {protected String name;public Animal(String name) {this.name = name;}
}
另外我們再提供一組接口, 分別表示 "會飛的", "會跑的", "會游泳的"
public interface IRunning {void run();
}public interface ISwiming {void swim();
}public interface IFlying {void fly();
}
下面我們創建幾個具體的動物:
貓,會跑:
public class Cat extends Animal implements IRunning{public Cat(String name) {super(name);}@Overridepublic void run() {System.out.println(this.name + "正在用四條腿跑");}
}
魚,會游泳:
public class Fish extends Animal implements ISwiming{public Fish(String name) {super(name);}@Overridepublic void swim() {System.out.println(this.name + "正在用尾巴游泳");}
}
鴨子,會跑會游泳又會飛:
public class Duck extends Animal implements ISwiming,IFlying,IRunning{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”,而類與接口之間的關系就像是這個類具有XX特性。
接口間的繼承
在Java中,類和類之間是單繼承的,一個類可以實現多個接口,接口與接口之間可以多繼承。即:用接口可以達到多繼承的目的。
接口可以繼承一個接口, 達到復用的效果. 使用 extends 關鍵字。
interface IRunning {void run();
}
interface ISwimming {void swim();
}interface IAmphibious extends IRunning, ISwimming {}class Frog implements IAmphibious {}
//注意Frog類要重寫run()和swim()方法
淺拷貝與深拷貝
Java 中內置了一些很有用的接口, Cloneable 就是其中之一。一個類實現Clonable接口代表這個類是可克隆的。
Object類是Java默認提供的一個類,所有的類都默認繼承自Object類,這個類中存在一個clone方法,調用這個方法可以創建一個對象的拷貝。
觀察下列代碼:
class Animal implements Cloneable {public String name;@Overridepublic Animal clone() {Animal o = null;try {o = (Animal)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return o;}public Animal(String name){this.name=name;}
}public class test {public static void main(String[] args) {Animal animal = new Animal("大黃");Animal animal2 = animal.clone();System.out.println(animal.name);System.out.println("-----------");System.out.println(animal2.name);}
}
其中try---catch語句使用到了異常的支持,這個后面再講。這段代碼主要內容是用一個Animal類實現了Cloneable接口,在Animal類中重寫了Object類中的clone方法,創建一個與對象相同的Animal對象并返回。代碼輸出結果如下:
可以看出animal2克隆了animal的成員變量name。
淺拷貝
我們在之前代碼的基礎上添加一個Age類,并在Animal類中實例化,在測試類中修改被克隆的對象animal2中的Age類的實例化對象a的成員變量age:
class Age{public int age = 10;
}
class Animal implements Cloneable {public String name;public Age a=new Age();@Overridepublic Animal clone() {Animal o = null;try {o = (Animal)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return o;}public Animal(String name){this.name=name;}
}public class test {public static void main(String[] args) {Animal animal = new Animal("大黃");Animal animal2 = animal.clone();System.out.println("修改前:"+animal.a.age);System.out.println("修改前:"+animal2.a.age);System.out.println("-----------");animal2.a.age=20;System.out.println("修改后:"+animal.a.age);System.out.println("修改后:"+animal2.a.age);}
}
運行結果如下:
可以看出在單獨修改了animal2中對象的情況下?animal一起被改變了。由此看出aniimal和animal2共同使用對象a,所以這種拷貝被稱為淺拷貝。
深拷貝
class Age implements Cloneable{public int age = 10;@Overridepublic Object clone()throws CloneNotSupportedException {return super.clone();}
}
class Animal implements Cloneable {public String name;public Age a=new Age();@Overrideprotected Object clone()throws CloneNotSupportedException {//return super.clone();Animal tmp = (Animal)super.clone();tmp.a=(Age)this.a.clone();return tmp;}public Animal(String name){this.name=name;}
}public class test {public static void main(String[] args)throws CloneNotSupportedException{Animal animal = new Animal("大黃");Animal animal2 = (Animal)animal.clone();System.out.println("修改前:"+animal.a.age);System.out.println("修改前:"+animal2.a.age);System.out.println("-----------");animal2.a.age=20;System.out.println("修改后:"+animal.a.age);System.out.println("修改后:"+animal2.a.age);}
}
將Age類同樣實現Cloneable接口并重寫clone方法,再在Animal的clone方法中使用Age的clone方法克隆Age對象,這樣就實現了深拷貝,注意方法返回值的類型問題,以及在每個方法后加上
throws CloneNotSupportedException
這段處理異常的代碼。
運行結果: