Java面向對象筆記 • 【第4章 抽象類和接口】

全部章節   >>>>


本章目錄

4.1 抽象類

4.1.1 抽象方法和抽象類

4.1.2 抽象類的作用

4.1.3 實踐練習

4.2 final修飾符

4.2.1 final成員變量

4.2.2 final局部變量

4.2.3 final方法

4.2.4 final類

4.2.5 實踐練習

4.3 接口

4.3.1 接口的定義

4.3.2 接口的實現

4.3.3 抽象類和接口的區別

4.3.4 實踐練習

4.4 接口編程案例

4.4.1 接口編程實例

4.4.2 實踐練習

總結:


4.1 抽象類

如何定義圖形類計算周長的通用方法?

  • 不同的圖形類圖形計算周長的方式大相徑庭所以導致Shape類的calcPerimeter()方法無法運用某個固定的計算圖形周長的公式
  • 可以將calcPerimeter()方法定義爲抽象方法,抽象方法沒有具體的方法實現,該方法必須由其繼承的子類重寫,這樣該方法就起到了約束規範的作用,又不影響類最初的設計思路。

4.1.1 抽象方法和抽象類

定義抽象類語法

[訪問修飾符]   abstract  class  類名

定義抽象方法語法

[訪問修飾符]   abstract  返回類型  方法名([參數列表])

抽象類和抽象方法規則:

個抽象類中可以不定義抽象方法,但是隻要類中有一個抽象方法,則該類一定是抽象類。

抽象類不能被實例化,即不能被new創建一個實例對象。

如果一個子類繼承一個抽象類,則子類需要通過覆蓋的方式來重寫該抽象類中的所有抽象方法。如果子類沒有完全重寫抽象父類中所有的抽象方法,則子類仍是抽象的。

抽象方法可以與publicprotected複合使用,但不能與finalprivatestatic複合使用。

abstract 不能用於修飾屬性,不能用於修飾局部變量,也不能用於修飾構造

示例:圖形繼承關係中使用抽象類和抽象方法

// 抽象類 圖形Shape :

public abstract class Shape { // 抽象類 圖形
	private  String color;
 
	// 定義一個計算周長的抽象方法
	public abstract double calcPerimeter();
	// 定一個返回圖形子類型的方法
	public abstract String  getType();
	// 有參構造方法
	public Shape(String color){
		this.color=color;
		System.out.println("---執行了Shape類的構造方法---");
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
}

// 子類 三角形Triangle :

public class Triangle  extends Shape{ //子類 三角形
	private  double  x,y,z; //定義三角形邊
	 
	public Triangle(String color,double x,double y,double z) {
		super(color);	//調用父類構造器	
		this.setSide(x, y, z);
	}
    	public  void setSide(double x,double y,double z){//設置三角形三邊
		if(x>y+z || y>x+z || z>x+y){
		   System.out.println("三角形兩邊之和必須大於第三邊");
		   return ;
		}
		this.x=x, this.y=y,this.z=z;
	}
	public double calcPerimeter() {//重寫父類計算周長方法
		return x+y+z;
	}
	public String getType() {//重寫父類獲取圖形類型方法
		return "三角形";
	}
}

//子類 圓形Circle :

public class Circle extends Shape { //子類 圓形
	private  double r;//半徑
 
	public Circle(String color,double r) {
		super(color);
		this.r=r;
	}
	public double calcPerimeter() {//重寫父類計算周長方法
		return  2*Math.PI*r;
	}
	//重寫父類獲取圖形類型方法
	public String getType() {
		return "圓形";
	}
	public double getR() {
		return r;
	}
	public void setR(double r) {
		this.r = r;
	}

main方法

	public static void main(String[] args) { // 測試
		Shape triangle=new Triangle("紅色", 3, 4, 5);
		Shape circle=new Circle("紅色", 4);		
		System.out.println(triangle.getType()+" 周長="+triangle.calcPerimeter());
		System.out.println(circle.getType()+" 周長="+circle.calcPerimeter());
	}

4.1.2 抽象類的作用

避免子類設計的隨意性:

  • 抽象類不能被實例化,只能作爲父類繼承。
  • 從多個具有相同特徵的類中抽象出一個抽象類,以該抽象類作爲其子類的模板

體現了模板模式的設計理念:

  • 類作爲多個子類的通用模板
  • 子類在抽象類的基礎上進行擴展、改造,但子類總體上會保留抽象類的行爲方式
  • 編寫一個抽象父類,父類提供多個子類的通用方法,並且將一個或多個方法留給其子類實現,這就是一種模板模式

示例:在速度表應用上使用模板設計模式

// 抽象父類速度表 SpeedMeter ,該抽象類爲模板類

public abstract  class SpeedMeter { //抽象父類速度表,該抽象類爲模板類
	private  double trunRate; //轉速
	//將返回車輪半徑的方法定義爲抽象方法
	public abstract double getRedius();
	
   	 //定義計算速度的通用算法
	public  double  getSpeed(){
	             //速度=車輪半徑*2*π*轉速
	            return  2*3.14*getRedius()*getTrunRate();
	}
	public double getTrunRate() {
		return trunRate;
	}
	public void setTrunRate(double trunRate) {
		this.trunRate = trunRate;
	}
}

// 子類汽車速度表 CarSpeedMeter

public class CarSpeedMeter extends SpeedMeter{ //子類汽車速度表
	//重寫父類的獲取半徑的方法
	public double getRedius() {
		return 2.0;
	}
	public static void main(String[] args) {
	            //創建CarSpeedMeter對象
	           CarSpeedMeter csm=new CarSpeedMeter();
	           csm.setTrunRate(15);//設置轉速
	           System.out.println("當前汽車時速="+csm.getSpeed()+"公里/小時");
	}
}

SpeedMeter類中提供了速度表的通用算法,但一些具體的實現細節則推遲到其子類CerSpeedMeter類中實現。這是一種典型的模板模式

模板模式基本規則:

抽象父類僅定義使用的某些方法,將不能實現的部分抽象成抽象方法,留給其子類實現。

類中包含需要調用其他依賴的方法,這些被調方法既可以由父類實現,也可以由其子類實現。父類中提供的方法僅定義了一個通用算法,需要具體子類輔助實現。

4.1.3 實踐練習

 

4.2 final修飾符

  • final關鍵字可以用於修飾類、變量和方法
  • final修飾變量時,表示該變量一旦獲得了初始值就不可能被改變,final修飾的類不能被繼承,final修飾的方法可以被繼承但不能被重寫
  • final意味着終極。

4.2.1 final成員變量

  • 對於final修飾的成員變量而言,一旦賦初始值就不能被重新賦值
  • final修飾的類屬性只能靜態初始化塊或聲明該屬性時指定初始值
  • final修飾的實例屬性只能構造方法聲明該屬性時指定初始值。

示例:演示final成員變量使用

4.2.2 final局部變量

  • 系統不會對局部變量進行初始化,局部變量必須由程序員顯式初始化。因此,使用final修飾局部變量時,既可以在定義時指定默認值,也可以不指定默認值
  • final修飾的局部變量在定義時沒有指定默認值,則應在後面的代碼中對該final變量賦初始值,但只能賦值一次,不能重複賦值。
  • 如果final修飾的局部變量在定義時已經指定默認值,則後面代碼中不能對該變量賦值。

示例:演示final局部變量使用

4.2.3 final方法

  • final修飾的方法不可以被重寫
  • 如果不允許子類重寫父類的某個方法,則可以使用final修飾該方法

示例:演示final方法使用

public class Bank { 
                //將該方法定義爲final,不允許子類重寫該方法
                 public final void LowerInterestRates(){ 
	         System.out.println(“央行按照宏觀經濟情況進行統一降息,各銀行按照國家標準統一執行");
	}
}

public class ChinaBank extends Bank{	 
   	//如果子類重寫父類的fianl()方法,程序在編譯時將報錯
   	public final void LowerInterestRates(){
   }
}

4.2.4 final類

  • final修飾符修飾的類稱爲最終類,最終類不能有子類
  • final類通常固定作用用於完成某種標準功能
  • final不能被繼承以達到不能被修改的目的

示例:演示final類使用

public final class Bank {  // final類
	public void LowerInterestRates(){ 
	         System.out.println(“央行按照宏觀經濟情況進行統一降息,各銀行按照國家標準統一執行");
	}
}

public class ChinaBank extends Bank{ //報錯,final類不能有子類 
   		
   }
}

4.2.5 實踐練習

 

4.3 接口

舉例:生活中的接口

Java中的接口同生活中的接口一樣,體現的是一種能力。

4.3.1 接口的定義

語法:

[訪問修飾符] interface  接口名  extends  父接口1,[父接口2,...]

說明:

接口的訪問修飾符可以public和缺省訪問修飾符,如果省略public修飾符,系統默認使用缺省訪問修飾符

接口中只能定義公有的、靜態的常量,並且這些常量默認都是公有的、靜態的。

接口中的方法只能是公有的抽象方法,並且這些方法默認都是公有的、抽象的。

接口只能繼承多個接口,接口不能繼承類,也不能實現其他接口。

4.3.2 接口的實現

語法:

[訪問修飾符]  class  類名  implements  接口1,[接口2,...]

說明:

接口是一種標準的體現

接口不能用於創建實例,接口的主要作用是在設計程序時對其實現類進行規範和約束

接口的主要用途就是被實現類實現。

一個類可以實現多個接口,從而實現多繼承。

示例:設計一個具有輸入功能,並且防水、防塵功能的鍵盤,以及一個防水、防塵和防盜功能的防盜門

public interface  Input { //輸入接口
    	//定義輸入的標準,由其實現類實現具體的實現細節
	public abstract void input();  // abstract 可省略
}

public interface Function { //功能接口
	//接口只能定義常量, 而且必須是靜態常量
	public static final String DEEP="30米";//防水深度
	//防塵指數
   	 int INDEX=5;  //接口中的常量默認是公有的、靜態、終極的
	//防水功能
	public abstract void waterproof();
	//防塵功能
   	 void dust(); //接口中的方法默認是公有的、抽象的
}

 

public interface ExtendsFunction extends Function { //擴展功能
             	void  antiTheft(); //防盜
}
public class AntitheftDoor implements ExtendsFunction { //防盜門實現擴展功能接口
                   //實現防水功能
	public void waterproof() {
		System.out.println("我是防盜門採用高科技的防水技術,防水深度:"+DEEP);
	}
                    //實現防塵功能
	public void dust() {
		System.out.println("我是防盜門採用納米防塵技術防塵,防塵指數:"+INDEX+"顆星");
	}
                     //實現防盜功能
	public void antiTheft() {
		System.out.println("我是防盜門採用密碼匹配防盜技術");
	}
}

 

public class Keyboard implements Function,Input{ //鍵盤類實現功能接口和輸入接口
   	//實現防水功能
	public void waterproof() {
		System.out.println("我是鍵盤採用特殊的密封屏蔽技術實現防水,防水深度:"+DEEP);
	}
	 //實現防塵功能
	public void dust() {
		System.out.println("我是鍵盤採用全硅膠材料實現防塵功能,防塵指數:"+INDEX+"顆星 ");		
	}
    	//實現Input接口中的輸入功能
	public void input() {
		System.out.println("我是鍵盤可以將敲擊鍵盤上的數據輸入到計算機中");
	}
}

 

public class Tset{
            public static void main(String[] args) {
		   //創建鍵盤對象
		   Keyboard keyboard=new Keyboard();
		   keyboard.dust();//調用鍵盤的防塵方法
		   keyboard.waterproof();//調用鍵盤的防水方法
		   keyboard.input();//調用輸入方法
		   System.out.println("------------------------------------");
		   //創建防盜門對象
		   AntitheftDoor  antitheftDoor=new AntitheftDoor();
		   antitheftDoor.antiTheft();//調用防盜門的防盜方法
		   antitheftDoor.dust();//調用防盜門的防塵方法
		   antitheftDoor.waterproof();//調用防盜門的防水方法
	}
}

4.3.3 抽象類和接口的區別

相同點:

接口和抽象類都不能被實例化,它們都位於繼承樹的頂端,用於被其他類實現和繼承。

接口和抽象類都可以包含抽像方法,實現接口或繼承抽象類的普通子類都必須實現這些抽象方法

不同點:

接口中只能包含抽象方法,而抽象類則完全可以包含普通方法。

接口中不能定義靜態方法,而抽象類中可以定義靜態方法。

接口中只能定義靜態常量,不能定義普通變量,或非靜態的常量,而抽象類中則可以定義不同的屬性,也可以定義靜態的屬性。

接口中不包含構造器,而抽象類中可以包含構造器,抽象類中的構造器並不用於創建對象,而是讓其子類調用這些構造器來完成抽象類的初始化操作。

個類最多只能有一個直接父類,包括抽象類,而一個類可以實現多個接口。通過實現多個接口可以彌補Java單繼承的不足。

4.3.4 實踐練習

 

4.4 接口編程案例

什麼是面向接口編程?

面向接口編程就是先把客戶的業務邏輯線提取出來作爲接口,接口業務的具體實現通過該接口的實現類來完成。

當客戶需求變化時,只需編寫該業務邏輯的新的實現類,通過更改配置文件中接口的實現類就可以完成需求,而不需要改寫現有代碼,從而減少對系統的影響。

面向接口編程的優點:

降低程序的耦合性。在程序中緊密的聯繫並不是一件好的事情,因爲兩種事物之間聯繫越緊密,更換其中之一的難度就越大。

易於系統的擴展。

易於系統的維護。

4.4.1 接口編程實例

使用面向接口編程實現一個簡易的用戶管理系統

要求用戶按照系統在控制檯中的提示信息,做出相應的選擇

系統接收到用戶輸入的指令後,給出相應的提示信息

創建dto包,在該包中定義類UserInfo用於封裝用戶信息。

public class UserInfo { //用戶實體類
      private String name;
      private int age;
      private String birthday;
      private String address;
	  
       //省略屬性的setter和getter方法
}

創建dao,在該包中定義一個維護用戶信息的接口UserInfoDao,在該接口中定義3個抽象方法,它們的功能分別是刪除用戶、更新用戶信息和保存用戶。

public interface UserInfoDao { //維護用戶信息接口
            public abstract void deleteUser(UserInfo user);
            public abstract void updateUser(UserInfo user);
            public abstract void saveUser(UserInfo user);
}

在該dao定義一個實現UserInfoDao的用戶信息維護UserInfoDaoImpl,該類分別實現接口中所有的抽象方法。

public class UserInfoDaoImpl implements UserInfoDao { //實現用戶信息維護接口
	public void saveUser(UserInfo user) {
		System.out.println("執行新增方法");
		System.out.println("姓名:"+ user.getName() +"  年齡:"+ 			                    user.getAge() + "  生日:"+ user.getBirthday() + "  家庭地址:"+ user.getAddress());
	}
	public void updateUser(UserInfo user) {
		System.out.println("執行更新方法");
	}
	public void deleteUser(UserInfo user) {
		System.out.println("執行刪除操作");
                   }
}

創建business包,在該包中定義UserInfoAccess類,在該類定義UserInfoDao對象屬性,值爲實現UserInfoDao接口的具體對象

在UserInfoAccess類定義服務方法service()實現主體業務。

public class UserInfoAccess {
	private UserInfoDao userInfoDao=new UserInfoDaoImpl();
	
	public void service(){
		System.out.println("請選擇操作【1】添加【2】修改【3】刪除");
		Scanner input=new Scanner(System.in);
		String state=input.next();
		if("1".equals(state)){
			userInfoDao.saveUser();
		}else if("2".equals(state)){
			userInfoDao.updateUser();
		}else if("3".equals(state)){
			userInfoDao.deleteUser();
		}
	}
}

public class UserMain{
	 public static void main(String[] args) {
	       new UserInfoAccess().service();
	}
}

4.4.2 實踐練習

 

總結:

個抽象類中可以不定義抽象方法,但是隻要類中有一個抽象方法,則該類一定是抽象類

抽象類不能被實例化,只能作爲父類繼承

final關鍵字可以用於修飾類、變量和方法。final修飾變量時,表示該變量一旦獲得了初始值就不可能被改變final修飾的類不能被繼承,final修飾的方法可以被繼承但不能被重寫。

接口中只能定義公有的、靜態的常量,並且這些常量默認都是公有的、靜態的;接口中的方法只能是公有的抽象方法,並且這些方法默認都是公有的、抽象的。

接口只能繼承多個接口,接口不能繼承類,也不能實現其他接口。

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