第十三章:抽象類和接口
一.抽象類
父類中定義了子類的共同行爲
接口定義了類的共同行爲(包括非相關類的)
注意:
- 抽象類不可以創建對象,可以包含抽象方法,這些方法在具體的子類中實現
abstract class GeometircObject {
//成員變量
private String color;
private boolean filled;
//構造方法只能被子類訪問,所以用protected修飾
protected GeometircObject (){}
//訪問器getters&修改器setters
public boolean isFilled() {
return filled;
}
public void setFilled(boolean filled) {
this.filled = filled;
}
public void setColor(String color) {
this.color = color;
}
public String getColor() {
return color;
}
// 抽象方法,只有定義沒有實現,需要被子類實現
abstract double getArea();
// 普通方法
double devideArea() {
return getArea() / 2;
}
}
- 抽象方法只有定義沒有實現,在具體的子類中實現,一個包含抽象方法的類必須聲明爲抽象類
- 抽象類的構造方法定義爲protected,因爲它只能被子類調用
1.抽象類與子類總結
- 在抽象類擴展的非抽象子類中,所有的抽象方法都要被實現,抽象方法都是非靜態的
- 抽象類不能使用new操作符來初始化
- 包含抽象方法的類必須是抽象的,但是可以定義一個不包含抽象方法的抽象類
abstract class GeometircObject {
//不包含抽象方法的抽象類
double devideArea() {
return 2;
}
}
- 子類可以覆蓋父類的方法,並將它定義爲abstract,這種情況下子類也必須是abstract
abstract class GeometircObject {
// 抽象方法,需要被子類實現
abstract double getArea();
abstract double getPrimeter();
}
abstract class Rectangle extends GeometircObject {
private double width;
private double height;
public Rectangle(double width,double height) {
this.width=width;
this.height=height;
}
//只實現了getArea方法,但是沒有實現getPrimeter方法,所以用abstract修飾
public double getArea() {
return width*height;
}
}
class RectangleChild extends Rectangle {
//如果父類只有含參構造方法,那子類必須要實現,否則構造不出父類,也就構造不出自己了,除非父類有一個或默認爲無參構造
private double width;
private double height;
public RectangleChild(double width,double height) {
super(width,height);
}
//實現父類沒有實現的getPrimeter方法
public double getPrimeter() {
return (width+height)*2;
}
}
- 即使父類是具體的,子類也可以是抽象的
- 不能使用new操作符創建一個對象,但是可以將抽象類當做一種數據類型
- abstract修飾符就是要求子類(覆蓋)這個方法,調用可以以多態的方式調用子類覆蓋後的方法
public static void main(String[] args) {
//abstract修飾的getArea()由Circle子類實現,可以使用多態動態調用子類覆蓋後的方法
GeometircObject circle = new Circle(3);
System.out.println(circle.getArea());
}
二.抽象的Numer類
Number是抽象包裝類,是BigInteger和BigDecimal的抽象父類
//byteValue和shortValue由inValue()方法得來,所以它不是抽象方法
byte byteValue(){
return (byte)intValue();
}
short shortValue(){
return (short)intValue();
}
//抽象方法
abstract int intValue();
abstract double doubleValue();
……
三.Calendar和GregorianCalendar
GregorianCalendar是抽象類Calendar的抽象子類
GregorianCalendar和Calendar有很多方法,這裏就不一一介紹了
值得一提的是Calendar類中有很多常量
例:YEAR 年
MONTH 月(0代表一月)
DAY_OF_WEEK (一週的天數,1是星期日)
……
public static void main(String[] args) {
// 創建GregorianCalendar實例
Calendar calendar = new GregorianCalendar();
// 打印當前年-月-日 備註:月份中0代表1月
System.out.println(calendar.get(Calendar.YEAR) + "-" + calendar.get(Calendar.MONTH) + "-"
+ calendar.get(Calendar.DAY_OF_MONTH));
}
//結果:2020-1-27 (實際是2020年2月27日)
四.接口
接口是一種與類相似的結構,只包含常量和抽象方法
接口的目的是指明多個相關或不相關的多個對象的共同行爲
語法
修飾符 interface 接口名{
//常量聲明 默認使用public static final 修飾
public static final int NUMBER=1; //等價於int NUMBER=1;
//方法簽名 默認使用public abstract 修飾
public abstract void function();//等價於void function();
}
- 不能使用new操作符創建接口實例
- 實現接口使用的關鍵字是inplements
public static void main(String[] args) {
//使用接口CouldCall作爲引用變量的類型
CouldCall animal = new Tiger();
System.out.println(animal.callFunction());
}
}
//可食用接口
interface CouldEat {
// 烹飪方法
public abstract String cookingFunction();
}
//叫聲接口
interface CouldCall {
// 叫聲
public abstract String callFunction();
}
//動物類
class Animal {
}
//老虎繼承自動物類並且實現叫聲接口,切記:老虎不能喫,禁食野味,愛自己也愛護他人!
class Tiger extends Animal implements CouldCall {
public String callFunction() {
return "ao";
}
}
//雞繼承自動物類,實現叫聲接口和可以食用接口
class Chicken extends Animal implements CouldCall, CouldEat {
public String cookingFunction() {
return "Broil";
}
public String callFunction() {
return "gogogo";
}
可以使用接口作爲引用變量的數據類型或類型轉換的結果
五.Comparable接口
//Comparable是一個泛型接口
interface Comparable<E>{
//比較方法返回一個int類型值
public int compare(E object);
}
instanceof 關鍵字用於判斷是否是此類的實例
//判斷animal是否是Animal的實例
System.out.println(animal instanceof Animal);//true
六.Cloneable接口
Cloneable給出了一個可克隆的對象
正常接口應該包含常量和抽象方法,但是Cloneable接口是空的
public interface Cloneable{}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] array = { 3, 5, 4, 6 };
int[] array2 = array.clone();
// 克隆實際上是創建了一個新的對象
System.out.println(array == array2);
array2[2] = 2;
printArray(array);
printArray(array2);
}
public static void printArray(int[] list) {
for (int i : list) {
System.out.print(i + " ");
}
System.out.println();
}
//結果
//false
//3 5 4 6
//3 5 2 6
實現Cloneable接口
//定義Cloneable 接口
interface Cloneable {
}
//Circle類實現Cloneable 接口
class Circle extends GeometircObject implements Cloneable {
//……
@Override
public Object clone() throws CloneNotSupportedException {
// 調用父類的Clone方法,會拋出一個CloneNotSupportedException的異常
return super.clone();
}
}
下圖是clone方法在Object類中的實現,可以看到使用native修飾的,由c語言編寫的,並且只能由包內類和子類可以訪問
七.接口與抽象類的區別
一個類只能繼承一個父類,但是可以實現多個接口
抽象類 | 接口 | |
---|---|---|
變量 | 無限制 | public static final 修飾 |
構造方法 | 通過構造方法鏈繼承構造方法,不能通過new操作符創建對象 | 不能通過new操作符創建對象 |
方法 | 無限制 | public abstract修飾 |
接口可以繼承其他接口,這樣的接口稱爲子接口
所有的類共享一個根類Object,但是接口沒有共同的根,接口可以定義一種類型,一個接口變量可以引用任何實現改接口的類的實例
類名可以是名詞,接口名可以是形容詞和名次
強的“是一種”關係用類來描述 例如:公曆是日曆的一種
弱的“是一種”關係用接口來描述 例如:所有的字符串都是可比較的
注意
接口可以擴展其他的接口而不是類,一個類可以擴展它父類的同時實現多個接口
八.Rational類
Rational類用於處理有理數,具體的方法就不一一描述了
Rational類沒有提供分子、分母的set方法,也就是說值不可改變,像String和基本數值類型的包裝類一樣
Rational類有嚴格的限制,容易溢出,可以使用BigInteger表示分子和分母
九.類的設計原則
- 內聚性 各司其職,內聚到一個
- 一致性 名字和方法一致性
- 封裝性 保護和維護私有數據
- 清晰性 方法設計,數據導入
- 完整性 提供多種方案實現不同的需求
- 實例和靜態 設爲靜態,類名直接調用
- 繼承和聚合 “是一種”和“具有”的關係
- 接口和抽象類 弱“是一種”和強“是一種”的關係
每個接口都被編譯成獨立的字節碼文件
深複製和淺複製
class Course implements Cloneable{
public Object clone() {
//深複製
Course c=(Course)super.clone();
c.student=student.clone();
//淺複製
c.student=super.clone();
}
}
十.總結
通過對本章的學習,我大致學會了使用抽象類和接口,以及他們使用的場景和規則,還學會了 幾個具有代表性的類,掌握了接口和抽象類的區別,最後,懂得了類的設計原則。
加油!第十四章待更……