java介面的使用(二)
技術標籤:java
在繼承體系中,一個類只能繼承一個父類。而對於介面而言,一個類是可以實現多個介面的,這叫做介面的多實現。並且,一個類能繼承一個父類,同時實現多個介面。
注意事項:
使用介面的時候,需要注意:
- 介面是沒有靜態程式碼塊或者構造方法的。
- 一個類的直接父類是唯一的,但是一個類可以同時實現多個介面。
格式:
public class MyInterfaceImpl implements MyInterfaceA, MyInterfaceB {
// 覆蓋重寫所有抽象方法
} - 如果實現類所實現的多個介面當中,存在重複的抽象方法,那麼只需要覆蓋重寫一次即可。
- 如果實現類沒有覆蓋重寫所有介面當中的所有抽象方法,那麼實現類就必須是一個抽象類。
- 如果實現類實現的多個介面當中,存在重複的預設方法,那麼實現類一定要對衝突的預設方法進行覆蓋重寫。
- 一個類如果直接父類當中的方法,和介面當中的預設方法產生了衝突,優先用父類當中的方法。
實戰:
介面A
package cn.itcast.day10.demo02;
public interface MyInterfaceA {
// 錯誤寫法!介面中不能有靜態程式碼塊
// static{
//
// }
// 錯誤寫法!介面中不能有構造方法
// public MyInterfaceA(){}
public abstract void methodA();
public abstract void methodAbs();
public default void methodDefault(){
System.out.println("預設方法AAA");
}
}
介面B
package cn.itcast.day10.demo02;
public interface MyInterfaceB {
// 錯誤寫法!介面不能有靜態程式碼塊
// static {
//
// }
// 錯誤寫法!介面不能有構造方法
// public MyInterfaceA(){
//
// }
public abstract void methodB();
public abstract void methodAbs();
public default void methodDefault(){
System.out.println("預設方法BBB");
}
}
實現類實現介面A,B; 沒有覆蓋重寫介面A,B中所有的抽象方法,因此該類必須是抽象類
package cn.itcast.day10.demo02;
public abstract class MyInterfaceAbstract implements MyInterfaceA, MyInterfaceB{
@Override
public void methodA() {
}
// @Override
// public void methodB() {
//
// }
@Override
public void methodAbs() {
}
@Override
public void methodDefault(){
}
}
實現類覆蓋重寫了A,B介面中的所有抽象方法,並對衝突的預設方法進行了覆蓋重寫
package cn.itcast.day10.demo02;
public class MyInterfaceImpl /*extends Object*/ implements MyInterfaceA, MyInterfaceB{
@Override
public void methodA() {
System.out.println("覆蓋重寫了A方法");
}
@Override
public void methodB() {
System.out.println("覆蓋重寫了B方法");
}
@Override
public void methodAbs() {
System.out.println("覆蓋重寫了AB介面中都有的抽象方法");
}
@Override
public void methodDefault(){
System.out.println("對多個介面當中衝突的預設方法進行覆蓋重寫");
}
}
一個類如果直接父類當中的方法,和介面當中的預設方法產生了衝突,優先用父類當中的方法。
父類:
package cn.itcast.day10.demo02;
public class Fu {
public void method(){
System.out.println("父類方法");
}
}
介面:
package cn.itcast.day10.demo02;
public interface MyInterface {
public default void method(){
System.out.println("介面的預設方法");
}
}
實現類,繼承父類方法並且實現介面
package cn.itcast.day10.demo02;
public class Demo01Interface {
public static void main(String[] args) {
Zi zi = new Zi();
zi.method();
}
}
結果如下所示:
- 類與類之間是單繼承的。直接父類只有一個。
- 類與介面之間是多實現的。一個類可以實現多個介面。
3. 介面與介面之間是多繼承的。
注意事項:
- 多個父介面當中的抽象方法如果重複,沒關係。
2. 多個父介面當中的預設方法如果重複,那麼子介面必須進行預設方法的覆蓋重寫,【而且帶著default關鍵字】。
父類介面A
package cn.itcast.day10.demo03;
public interface MyInterfaceA {
public abstract void methodA();
public abstract void methodCommon();
public default void methodDefault(){
System.out.println("AAA");
}
}
父類介面B
package cn.itcast.day10.demo03;
public interface MyInterfaceB {
public abstract void methodB();
public abstract void methodCommon();
public default void methodDefault(){
System.out.println("BBB");
}
}
子介面繼承介面A,B
package cn.itcast.day10.demo03;
public interface MyInterface extends MyInterfaceA, MyInterfaceB{
public abstract void method();
@Override
public default void methodDefault(){
}
}
介面中的多型性
程式碼當中體現多型性,其實就是一句話:父類引用指向子類物件。
格式:
父類名稱 物件名 = new 子類名稱();
或者:
介面名稱 物件名 = new 實現類名稱();
下面介紹類中的多型性:
父類:
package cn.itcast.day10.demo04;
public class Fu {
public void method(){
System.out.println("父類方法");
}
public void methodFu(){
System.out.println("父類特有方法");
}
}
子類方法
package cn.itcast.day10.demo04;
public class Zi extends Fu{
@Override
public void method(){
System.out.println("子類方法");
}
}
main方法
package cn.itcast.day10.demo04;
public class Demo01Multi {
public static void main(String[] args) {
// 使用多型的寫法
// 左側父類的引用,指向了右側子類的物件
Fu obj = new Zi();
obj.method();
obj.methodFu();
}
}
執行結果:
多型中成員變數的訪問規則:
訪問成員變數的兩種方式:
- 直接通過物件名稱訪問成員變數:看等號左邊是誰,優先用誰,沒有則向上找。
- 間接通過成員方法訪問成員變數:看該方法屬於誰,優先用誰,沒有則向上找。
在多型的程式碼當中,成員方法的訪問規則是:
看new的是誰,就優先用誰,沒有則向上找。
口訣:編譯看左邊,執行看右邊。
對比一下:
成員變數:編譯看左邊,執行還看左邊。
成員方法:編譯看左邊,執行看右邊。
父類
package cn.itcast.day10.demo05;
public class Fu {
int num = 10;
public void showNum(){
System.out.println(num);
}
public void method(){
System.out.println("父類方法");
}
public void methodFu(){
System.out.println("父類特有方法");
}
}
子類
package cn.itcast.day10.demo05;
public class Zi extends Fu{
int num = 20;
int age = 16;
@Override
public void showNum(){
System.out.println(num);
}
@Override
public void method(){
System.out.println("子類方法");
}
public void methodZi(){
System.out.println("子類特有方法");
}
}
main1方法,訪問成員變數
package cn.itcast.day10.demo05;
public class Demo01MultiField {
public static void main(String[] args) {
// 使用多型的寫法,父類引用指向子類物件
Fu obj = new Zi();
System.out.println(obj.num);
System.out.println("=======");
// 子類沒有覆蓋重寫,就是父:10
// 子類如果覆蓋重寫,就是子:20
obj.showNum();
}
}
結果如下所示:
main方法,訪問成員方法
package cn.itcast.day10.demo05;
public class Demo02MultiMethod {
public static void main(String[] args) {
Fu obj = new Zi();// 多型
obj.method();// 父子都有,優先用子
obj.methodFu();//子類沒有,父類有,向上查詢父類
// 編譯看左邊,執行看右邊,左邊是Fu,Fu當中沒有methodZi方法,所以編譯報錯。
// obj.methodZi();
}
}
結果如下所示:
物件的向上、向下轉型
實戰一
父類
package cn.itcast.day10.demo06;
public abstract class Animal {
public abstract void eat();
}
子類1
package cn.itcast.day10.demo06;
public class Cat extends Animal{
@Override
public void eat() {
System.out.println("貓吃魚");
}
// 子類特有方法
public void catchMouse(){
System.out.println("貓抓老鼠");
}
}
子類2
package cn.itcast.day10.demo06;
public class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃SHIT");
}
public void watchHouse(){
System.out.println("狗看家");
}
}
mian函式1
package cn.itcast.day10.demo06;
public class Demo01Main {
public static void main(String[] args) {
// 物件的向上的轉型,就是:父類引用指向子類物件
Animal animal = new Cat();
animal.eat();// 貓吃魚
// 向下轉型,進行"還原"動作
Cat cat = (Cat) animal;
cat.catchMouse();// 貓抓老鼠
// 下面是錯誤的向下轉型
// 本來new的時候是一隻貓,非要當作狗
// 錯誤寫法!編譯不會報錯,但是執行會出現異常
Dog dog = (Dog) animal;
}
}
執行結果
mian方法二
向下轉型的判斷
如何才能知道一個父類引用的物件,本來是什麼子類?
格式:
物件 instanceof 類名稱
這將會得到一個boolean值結果,也就是判斷前面的物件能不能當做後面型別的例項。
package cn.itcast.day10.demo06;
public class Demo02Instanceof {
public static void main(String[] args) {
Animal animal = new Dog();
animal.eat();// 狗吃SHIT
// 如果希望呼叫子類特有的方法,需要向下轉型
// 判斷一下父類引用animal本來是不是Dog
if (animal instanceof Dog){
Dog dog = (Dog) animal;
dog.watchHouse();
}
// 判斷一下animal本來是不是Cat
if (animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
giveMeAPet(new Dog());
}
public static void giveMeAPet(Animal animal){
if (animal instanceof Dog){
Dog dog = (Dog) animal;
dog.watchHouse();
}
if (animal instanceof Cat){
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
}
實戰二(介面中的多型)
computer類
package cn.itcast.day10.demo07;
public class Computer {
public void powerOn() {
System.out.println("膝上型電腦開機");
}
public void powerOff() {
System.out.println("膝上型電腦關機");
}
// 使用USB裝置的方法,使用介面作為方法的引數
public void useDevice(USB usb) {
usb.open(); // 開啟裝置
if (usb instanceof Mouse) { // 一定要先判斷
Mouse mouse = (Mouse) usb; // 向下轉型
mouse.click();
} else if (usb instanceof Keyboard) { // 先判斷
Keyboard keyboard = (Keyboard) usb; // 向下轉型
keyboard.type();
}
usb.close(); // 關閉裝置
}
}
USB介面
package cn.itcast.day10.demo07;
public interface USB {
public abstract void open(); // 開啟裝置
public abstract void close(); // 關閉裝置
}
鍵盤類實現USB介面
package cn.itcast.day10.demo07;
// 鍵盤就是一個USB裝置
public class Keyboard implements USB {
@Override
public void open() {
System.out.println("開啟鍵盤");
}
@Override
public void close() {
System.out.println("關閉鍵盤");
}
public void type() {
System.out.println("鍵盤輸入");
}
}
滑鼠類實現USB介面
package cn.itcast.day10.demo07;
// 滑鼠就是一個USB裝置
public class Mouse implements USB {
@Override
public void open() {
System.out.println("開啟滑鼠");
}
@Override
public void close() {
System.out.println("關閉滑鼠");
}
public void click() {
System.out.println("滑鼠點選");
}
}
main方法:
package cn.itcast.day10.demo07;
public class DemoMain {
public static void main(String[] args) {
// 首先建立一個膝上型電腦
Computer computer = new Computer();
computer.powerOn();
// 準備一個滑鼠,供電腦使用
// Mouse mouse = new Mouse();
// 首先進行向上轉型
USB usbMouse = new Mouse(); // 多型寫法
// 引數是USB型別,我正好傳遞進去的就是USB滑鼠
computer.useDevice(usbMouse);
// 建立一個USB鍵盤
Keyboard keyboard = new Keyboard(); // 沒有使用多型寫法
// 方法引數是USB型別,傳遞進去的是實現類物件
computer.useDevice(keyboard); // 正確寫法!也發生了向上轉型
// 使用子類物件,匿名物件,也可以
// computer.useDevice(new Keyboard()); // 也是正確寫法
computer.powerOff();
System.out.println("==================");
method(10.0); // 正確寫法,double --> double
method(20); // 正確寫法,int --> double
int a = 30;
method(a); // 正確寫法,int --> double
}
public static void method(double num) {
System.out.println(num);
}
}