抽象類、內部抽象類、模板設計演算法
阿新 • • 發佈:2018-10-31
抽象類的定義與使用
定義: 抽象類只是在普通類的基礎上擴充了一些抽象方法而已。
抽象方法:
- 只宣告未定義的方法(沒有方法體)
- 所有抽象方法要求使用abstract來定義,並且抽象方法所在類必須用abstract來定義,表示抽象類。
抽象類的使用原則:
- 所有抽象類必須有子類(abstract與final不能同時使用,是因為final宣告的類不能有子類);
- 抽象類的子類必須覆寫抽象類的所有抽象方法,前提是這個子類不在是一個抽象類,如果是子類是一個抽象類,可以不全覆寫父類抽象方法(abstract與private不能同時使用);
- 如果抽象類需要例項化物件,必須通過子類向上轉型為其例項化(抽象類無法建立例項化物件)
abstract class Person //抽象類 { private String name; abstract public void fun1(); //抽象方法 //abstract public void func2(); //兩個抽象方法必須全覆寫 } class Student extends Person { public void fun1() //重寫抽象方法 { System.out.println("子類繼承抽象類"); } } public class Abstract { public static void main(String[] args) { Person p=new Student(); //向上轉型 p.fun1(); //呼叫的子類中被覆寫的fun1(); } }
抽象類的相關規定
1.抽象類允許提供構造方法,並且子類也遵循物件例項化流程,先呼叫父類構造方法而後呼叫子類構造方法。
物件例項化操作包括:
- 進行類載入
- 進行類物件的空間開闢
- 進行類物件的屬性初始化(構造方法)
/////面試題 abstract class Person //抽象類 { public Person() //3.呼叫父類構造 { this.fun1(); //4.呼叫fun1,發現父類中fun1為抽象類,就調子類中覆寫的fun1 } abstract public void fun1(); //抽象方法 } class Student extends Person { private int num=100; //7.調子類構造時初始化屬性變為100 public Student(int num) //2.呼叫子類構造 { this.num=num; //賦值後num變為30 } public void fun1() //5.此時還沒有調子類構造,屬性是在調建構函式時初始化,所以此時還沒有初始化屬性 { System.out.println(this.num); // 6.沒有初始化,屬性預設值為0 } } public class Abstract { public static void main(String[] args) { new Student(30);//1.例項化子類物件 結果為0 new Student(30).fun1(); //結果為0 30 ,因為先調了父類構造,所以有0 } }
2.抽象類中允許不定義任何的抽象方法,但是此時抽象類依然無法直接建立例項化物件。
3.abstract不能與final一起使用:abstract定義類必須有子類,final定義類不能有子類;
abstract不能與private一起使用:abstract定義方法必須被重寫,private定義方法在子類不可見。
內部抽象類
子類可以只覆寫父類的直接抽象方法,不管父類內部類抽象方法;如果需要重寫父類內部類抽象方法,可以在子類中定義一個父類內部抽象類的子類來重寫:
abstract class Person
{
public abstract void fun1();
abstract class B
{
public abstract void fun2();
}
}
class Student extends Person
{
public void fun1() //對父類直接抽象方法覆寫
{
}
class C extends B //重新定義一個子類
{
public void fun2()
{
}
}
}
模板設計演算法
模板設計演算法基於抽象類,核心是封裝演算法。模板方法定義了一個演算法的步驟,並允許子類為一個或多個步驟提供具體實現。
模板(模板方法)模式:
在一個方法中定義一個演算法的骨架,並將一些具體步驟延遲到子類實現。模板模式使得子類可以在不改變演算法結構的基礎上,重新定義演算法中的某些步驟。
如下列的咖啡因飲料:咖啡和茶都有相同的步驟:煮沸水、泡咖啡或者浸泡茶、向咖啡或茶新增東西、將飲料倒入杯中,這四個步驟咖啡和茶都有,即是相同的演算法結構,那麼就可以把這四個步驟定義在一個演算法模板中,不同的步驟子類重寫:
import java.util.Scanner;
abstract class CaffeineBerverage //父類是咖啡因飲料
{
//模板方法 宣告為final:只允許子類使用,不允許覆寫
final void prepareRecipe()
{
boilWater();
brew();
if(customerWantsCondiments())
{
addCondiments();
}
pourInCup();
}
public void boilWater() //燒水
{
System.out.println("將水煮沸");
}
public void pourInCup()
{
System.out.println("將飲料調入杯中");
}
////鉤子方法:子類選擇性覆蓋
boolean customerWantsCondiments() //顧客是否想要新增東西,因為有的顧客不想新增東西
{
return true;
}
abstract public void brew();//處理飲料的方式
abstract public void addCondiments(); //向飲料里加東西
}
class Coffee extends CaffeineBerverage //咖啡
{
public void brew()
{
System.out.println("沖泡咖啡");
}
public void addCondiments()
{
System.out.println("加糖和奶");
}
boolean customerWantsCondiments() //重寫
{
System.out.println("請問您想要加糖或奶嗎? y/n");
String result=getUserInfo();
if(result.equals("y"))
{
return true;
}
else
{
return false;
}
}
private String getUserInfo()
{
Scanner scanner=new Scanner(System.in);
String str=scanner.nextLine();
return str;
}
}
class Tea extends CaffeineBerverage
{
public void brew()
{
System.out.println("浸泡茶葉");
}
public void addCondiments()
{
System.out.println("加檸檬");
}
}
public class Abstract
{
public static void main(String[] args)
{
CaffeineBerverage coffee=new Coffee();
coffee.prepareRecipe();
CaffeineBerverage tea=new Tea();
tea.prepareRecipe();
}
}