Java基礎自學筆記——第十三章:抽象類和接口

第十三章:抽象類和接口

一.抽象類

父類中定義了子類的共同行爲

接口定義了類的共同行爲(包括非相關類的)

注意:

  • 抽象類不可以創建對象,可以包含抽象方法,這些方法在具體的子類中實現
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();
	}
}

十.總結

通過對本章的學習,我大致學會了使用抽象類和接口,以及他們使用的場景和規則,還學會了 幾個具有代表性的類,掌握了接口和抽象類的區別,最後,懂得了類的設計原則。

加油!第十四章待更……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章