抽象類
class Shape {
public void draw() {
// 啥都不用幹
}
}
class Cycle extends Shape {
@Override
public void draw() {
System.out.println("○");
}
}
class Rect extends Shape {
@Override
public void draw() {
System.out.println("□");
}
}
class Flower extends Shape {
@Override
public void draw() {
System.out.println("♣");
}
}
/////////////////////////////華麗麗的分割線//////////////////////
// Test.java
public class Test {
public static void main(String[] args) {
Shape shape1 = new Flower();
Shape shape2 = new Cycle();
Shape shape3 = new Rect();
drawMap(shape1);
drawMap(shape2);
drawMap(shape3);
}
// 打印單個圖形
public static void drawShape(Shape shape) {
shape.draw();
}
}
看完上面代碼可以發現,父類Shape
中的draw();
方法並沒有實現具體的功能,代碼中調用的draw();
都是基於子類的draw();
方法來完成的,這種方法就可以定義爲抽象方法(abstract method),包含抽象方法的類就叫做抽象類(abstract class).
abstract
用abstract關鍵字來標識抽象方法和抽象類
abstract class Shape {
abstract public void draw();
}
注意:
- 抽象類中不能有具體的實現,所以
abstract public void draw();
後面不可以帶{}
,切記 - 包含抽象方法的類叫做抽象類
- 抽象類中可以有抽象方法 也可以有非抽象方法或成員變量
- 抽象類是不能被實例化的(不能被new)。
要想使用只能創建該抽象類的子類 然後讓子類重寫抽象類中的抽象方法 - 所以可以說抽象類就是爲了被繼承的,要注意一旦被繼承之後一定要重寫抽象類裏的方法
- 但如果是抽象類A繼承抽象類B, A選擇可重寫也可不重寫B中的方法
- 如果抽象類中的方法已經重寫了,那麼被繼承之後就不用重寫
- 抽象方法不能是私有的
抽象類的作用
抽象類的存在就相當於多了一層代碼的校驗,像Shape
這樣的類我們並不會直接使用, 而是使用它的子類. 萬一不小心創建了Shape
的實例, 編譯器會及時提醒我們.
比如說上述繪製圖形的代碼
如果說本意是想繪製方塊,而編寫代碼時用的是父類Shape
的draw();
方法,這樣編譯器並不會報錯,但是運行結果並不是我們想要的,排查錯誤時不易被發現
但如果我們將draw();
方法設置爲抽象方法,由於抽象類無法實例化,所以無法調用裏面的draw();
方法,這樣就可以預防我們出錯
接口
接口是抽象類的更進一步. 抽象類中還可以包含非抽象方法, 和字段. 而接口中包含的方法都是抽象方法, 字段只能包含靜態常量
比如說打印圖形的代碼,如果Shape類中沒有非抽象方法和字段,那麼就可以將上面代碼改寫成
interface IShape {
void draw();
}
class Cycle implements IShape {
@Override
public void draw() {
System.out.println("○");
}
}
class Rect implements IShape {
@Override
public void draw() {
System.out.println("□");
}
}
class Flower implements IShape {
@Override
public void draw() {
System.out.println("♣");
}
}
interface
- 接口用關鍵字interface定義
- 接口中的方法全部不能有具體的實現==》接口中的方法默認都是抽象方法,即默認是public abstract,所以可以省略不寫
- 接口當中的方法要儘量簡潔
- 接口中的成員變量默認是public static final的 所以必須要初始化
- 接口不能單獨被實例化 不可以new==>接口存在的意義就是被是實現/繼承
- 接口名一般是以i開始
public interface IShape
implements
class Rect implements IShape{}
,用關鍵字implements實現接口- 類和接口之間的關係叫實現 只要一個普通類要實現這個接口,那麼接口當中的方法必須重寫
- 接口可以發生向上轉型
IShape iShape=new Rect();
接口的作用
-
接口的存在是爲了實現Java中的多繼承
class Abc implements IA,IB,IC。。。
或是class Cat extends Animal implements IRunning
-
接口和接口之間不能實現但是可以繼承,且可以繼承多個接口
抽象類和接口的使用
單從關鍵字上看extends
vs implements
,一個是拓展,一個是實現,拓展是指之前已經存在,將他更完善,而實現是之前沒有,要重新構造出來一個
所以繼承表達的意思是is-a
,而實現接口表達的是具有某種特性
還是用代碼來舉例子
先創建一個Animal類
class Animal {
protected String name;//這裏之所以用protected來實現封裝上篇已經提到,此處就不贅述
public Animal(String name) {
this.name = name;
}
}
再創建幾個接口
interface IRunning {
void run();
}
interface IEating {
void eat();
}
此時創建一個貓咪類,他首先是一個動物(extends Animal),其次貓咪可以跑來跑去,可以吃東西(也就是說有會跑會吃的特點)(implements IRunning,IEating),這樣一個貓咪類就建好了
class Cat extends Animal implements IRunning,IEating {
public Cat(String name) {
super(name);
}
@Override
public void run() {
System.out.println(this.name + "is running");
}
@Override
public void eat() {
System.out.println(this.name + "is eating");
}
}
抽象類和接口的區別
- 核心區別:
抽象類中可以包含非抽象方法, 和字段. 那麼普通方法和字段可以被子類直接使用(不必重寫)
接口中包含的方法都是抽象方法, 字段只能包含靜態常量,所以子類必須重寫所有的抽象方法 - 一個抽象類可以實現多個接口
接口不能繼承抽象類,但是接口可以用extends關鍵字繼承多個父接口