相關文章:
- 《面向物件再探究》:介紹了面向物件的基本概念
- 《詳解Java的物件創建》:介紹了物件的創建、構造器的使用
- 《一文打盡Java繼承的相關問題》:介紹了繼承的使用方式和注意事項
本文來介紹Java的抽象類和介面的使用,
1. 抽象類
在前面的文章中提到過:父類比子類更加抽象,子類比父類更加具體,
在《一文打盡Java繼承的相關問題》這篇文章中舉了動物和狗的例子:
public class Animal {
private String name;
private int age;
public Animal(String name, int age) {
this.name = name;
this.age = age;
}
public Animal() {
}
public void say() {
System.out.println("我是" + name + ",今年" + age + "歲了");
}
//getters and setters ...
}
public class Dog extends Animal {
private String address;
public Dog(String name, int age, String address) {
super(name, age);
this.address = address;
}
public Dog() {
}
public void say() {
System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "歲了,家住" + address + ",汪汪汪...");
}
public void watchDoor() {
System.out.println("我在" + address +"看門...");
}
//getters and setters ...
}
上面Dog類很自然地繼承了Animal類,沒毛病!但是仔細琢磨一下Animal類的say()方法,
動物是一個很寬泛的概念,如果寫代碼表示,我們平常見到的大部分生物都可以繼承該類,如下圖:
有這么多類繼承Animal類,那Animal類的say()方法這樣寫合適嗎?因為每種動物說話的方式都不同,而動物又是這么寬泛的一個概念,我們通常會new Dog()或new People(),但很少會去new Animal(),
所以Animal類的say()方法體對其來說就是雞肋一般的存在,因為即使有方法體,也會被其子類重寫,既然這樣那就干脆不要方法體了,
換句話說,我們將Animal類再進行更高層次地抽象,它具有各種動物都有的屬性,比如name、age,也有各種動物都有的行為,比如say,但是,Animal類并不具體實作該方法,具體的實作交給子類來做,
這樣一來,誰繼承了Animal類,誰就有了它的屬性和行為,子類不用管父類的行為是否合適,因為父類的行為“有名無實”,所以子類只需繼承這些“名”,具體的“實”則由子類來完成,
這樣的Animal類就是抽象類,
下面將上例中的Animal類修改為抽象類,Dog類無需改動:
public abstract class Animal {
private String name;
private int age;
public Animal(String name, int age) {//有參構造器
this.name = name;
this.age = age;
}
public Animal() {//無參構造器
}
public abstract void say();//抽象方法
public String getName() {//被具體實作的方法
return name;
}
public void setName(String name) {
this.name = name;
}
//getters and setters..
}
下面是抽象類的特點:
(一)抽象類被abstract關鍵字修飾,
public abstract class Animal {
//......
}
(二)類中沒有方法體的方法叫抽象方法,也需要使用abstract關鍵字修飾,
public abstract void say();//抽象方法
(三)有抽象方法的類一定是抽象類,
(四)沒有抽象方法的類也可以是抽象類,
(五)抽象類中可以有成員變數、構造器、被具體實作的方法,構造器不能是抽象的,
(六)抽象類不能被實體化,但是可以宣告一個抽象類變數
Animal animal = new Animal();//報錯: 'Animal' is abstract; cannot be instantiated
Anima animal;//抽象類變數,可行
我們以前遇到的類,比如Dog類,是用來描述物件的,但抽象類的方法沒有具體實作,所以它沒有足夠的資訊來描述物件,所以抽象類只能被繼承用來描述其子類而不能實體化,
(七)子類擴展抽象父類有兩種選擇:
- 當子類不是抽象類時,子類必須實作抽象父類的抽象方法:
public class Dog extends Animal {
//屬性、構造器、其他方法
//實作抽象父類的抽象方法
@Override
public void say() {
System.out.println("我叫" + super.getName() + ",今年" + super.getAge() + "歲了,家住" + address + ",汪汪汪...");
}
}
- 當子類是抽象類時,子類可以實作抽象父類的抽象方法,也可以選擇不實作,
public abstract class Dog extends Animal {
//屬性、構造器、其他方法
//可以選擇不實作父類的抽象方法
}
2. 介面
2.1. 什么是介面?
生活中有一種介面是大家每天都在用的,那就是插座,
不管是什么樣的電器,冰箱、電視、電腦、電風扇,只要買回來,就能插上通電,之所以這么便利,就是因為電器生產商和插座生產商都遵守了一個生產規范:我把插座生產成這個模樣,你把插頭也生產成這個模樣,我不管你電器內部是啥樣,你也不用管我的插座內部是啥樣,大家把產品生產好,各自賣給客戶,合作愉快,一起賺錢,這些產品如果以后壞了,那就再買一個遵守規范的就能繼續配套使用了,
想一想,如果沒有這個規范,插座和插頭生產的千奇百怪,買回來怎么用?只能把插座和冰箱拆開,用手接220V的電線了,
換句話說,介面就是生產規范 / 標準,或者雙方遵守的協議,只要雙方都遵守,那么就能愉快地交流、愉快地合作,
在Java開發中,一個軟體系統肯定不是由一個人完成的,而是由一個團隊完成的,那如何避免甲寫的類乙不能用,乙寫的類丙不能用呢,最后導致甲改了乙的代碼,乙改了丙的代碼?事先定好規范(介面),大家都遵守介面,只要我知道你的介面,那么我不需要知道你的具體代碼,就能呼叫你的類,
2.2. 介面的使用
掌握關于介面幾個特點就能愉快地寫介面了:
(一)Java中使用inteface關鍵字來宣告一個介面,介面必須是public的,只有公有了才能讓大家遵守:
public interface Runnable {
}
(二)介面中通常寫各種抽象方法,但只宣告,不能寫方法體,
public interface Runnable {
/*public abstract*/ void run();
}
(三)不必將方法宣告為public abstract ,在介面中的所有方法都默認的是public abstract修飾,
(四)介面中不能有成員變數、靜態代碼塊,
(五)介面中可以含有常量,常量默認是public static final修飾,
public interface Runnable {
/*public static final*/ int i = 1;
void run();
}
(六)類通過implements關鍵字實作介面,必須同時實作介面中的所有方法,
public class Dog implements Runnable {
@Override
public void run() {
System.out.println("跑得飛快");
}
//......
}
(七)如果實作介面的類是抽象類,可以不用實作介面中的方法,
(八)一個類可以同時繼承類和實作介面,
public class Dog extends Animal implements Runnable {
//......
}
(九)一個類可以實作多個介面,
public class Dog implements Runnable, Flyable {
//......
}
(十)介面之間可以繼承,并且允許多繼承,
public interface A {
//......
}
public interface B extends A, Runnable{
//......
}
(十一)介面不能被實體化,但是可以宣告一個介面變數,
Runnable runnable = new Runnable();//'Runnable' is abstract; cannot be instantiated
Runnable runnable;//介面變數,可行
3. 總結
抽象類用abstract關鍵字宣告,抽象類中除了可以有抽象方法(用abstract關鍵字宣告)外,還可以有普通類的成員變數、構造器、方法,不能被實體化,但可以宣告抽象類的變數,子類繼承抽象類要實作父類的抽象方法(如果子類是抽象的,則不用實作),
介面用interface關鍵字宣告,介面中只能有抽象方法、常量(忽略修飾符),不能被實體化,但可以宣告介面變數,介面之間可以繼承,且允許多繼承,類實作介面使用implements關鍵字,且必須實作介面中的抽象方法(如果類是抽象的,則不用實作),
總結了抽象類和介面的特點,發現抽象類好像也能作為“介面”使用,那有了抽象類,為什么還要有介面?
類只能單繼承,如果使用抽象類作為“介面”,這意味著一個類只能遵守一份“介面”,顯然不符合實際,而介面則靈活多了,
4. 關于我
如有錯誤,還請指正,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/108963.html
標籤:Java
上一篇:java_Lambda運算式
下一篇:PHP intdiv 數學函式
