1. 程式人生 > >Java抽象類全解析

Java抽象類全解析

一、抽象類的定義語法:
1.普通類可以直接產生例項化物件,並且在普通類之中可以包含有構
造方法、普通方法、static方法、常量、變數等內容,而所謂的抽象
類就是指在普通類的結構裡面增加抽象方法的組成部分。
所有的普通方法都會有個“{}”,表示方法體,有方法體的方法一定可
以被物件直接使用,而抽象方法指的是沒有方法體的方法,同時抽象
方法還必須使用abstract關鍵字進行定義。
擁有抽象方法的類一定屬於抽象類,抽象類要使用abstract宣告。
範例:定義抽象類:
abstract class A{//定義一個抽象類
   public void fun(){//抽象方法
       System.out.println("存在有方法體的方法!");
   }
   //此方法並沒有方法體的宣告,並且存在有abstract關鍵字,表示抽象方法
   public abstract void print();
}
public class A{//
   public static void main(String args[]){
      A a = new A();//A是抽象的;無法例項化
      a.fun();
      a.print(); 
   }
}
執行結果錯誤,不能直接對A類物件例項化。之所以不能夠例項化物件原因很簡單:當一個類的物件例項化之後就意味著這個物件可以呼叫類中的屬性或方法,但是在抽象類裡面存在有抽象方法,抽象方法沒有方法體,既然沒有方法體,怎麼可能去呼叫?既然不能呼叫,怎麼產生例項化物件?
抽象類的使用原則:
1.抽象類必須有子類,即:每一個抽象類一定要被子類所繼承
2.抽象類的子類(子類不是抽象類)必須要覆寫抽象類之中的全部抽象方法(強制子類覆寫)
3.抽象類的物件例項化需要依靠子類完成,採用向上轉型的方式處理
範例:正確使用抽象類:
abstract class A{//定義一個抽象類
   public void fun(){//抽象方法
       System.out.println("存在有方法體的方法!");
   }
   //此方法並沒有方法體的宣告,並且存在有abstract關鍵字,表示抽象方法
   public abstract void print();
}
//一個子類只能夠繼承一個抽象類,屬於單繼承侷限
class B extends A{//B類是抽象類的子類,並且是一個抽象類的子類,並且是一個普通類
   public void print(){//強制要求覆寫的方法
    System.out.println("Hello World !");
   }
}
public class TestDemo{//
   public static void main(String args[]){
      A a = new B();//向上轉型
      a.print(); //被子類所覆寫過的方法
   }
}
總結:
1.抽象類繼承子類裡面會有明確的方法覆寫要求,而普通類並沒有;2.抽象類只比普通類多了一些抽象方法的定義,其他的組成部分與普通類完全一樣; 
3.普通類物件可以直接例項化,但是抽象類的物件必須經過向上轉型之後才可以得到例項化物件。
雖然一個子類可以去繼承任意的一個普通類,可是從開發的實際要求來講,普通類最多不要去繼承另外一個普通類,而只能繼承抽象類。
二、抽象類的使用限制
1.抽象類裡面由於會存在一些屬性,那麼在抽象類之中一定會存在構造方法,目的:為屬性初始化,並且子類物件例項化的時候依然滿足於先執行父類構造,再呼叫子類構造的情況。
2.抽象類能不用使用final:因為抽象類必須有子類,而final定義的類不能夠有子類;
3.抽象類不允許使用static宣告,而內部的抽象類允許使用static宣告,使用static宣告的內部抽象類就相當於是一個外部抽象類,繼承的時候使用"外部類.內部類"的形式表示類名稱。
eg:
abstract class A {//定義一個抽象類
   //static定義的內部類屬於外部類
   static abstract class B {
     public abstract void print();
   }
}
class X extends A.B {
    public void print(){
  System.out.println("***********");
}
}
public class TestDemo{
   public static void main(String args []){
     A.B ab = new X();//向上轉型
     ab.print();
   }
}
4.任何情況下,如果要執行類中的static方法的時候,都可以在沒有物件的時候,直接呼叫,對於抽象類也是一樣。
eg:
abstract class A {
   public static void print(){
      System.out.println("Hello World!");
   }
}
public class TestDemo{
   public static void main(String args[]){
     A.print();
   }
}
5.有些時候,由於抽象類只需要一個特定的系統子類操作,所以可以忽略掉外部子類。
eg:
abstract class A {//定義一個抽象類
   public abstract void print();
   private static class B extends A {//內部抽象類子類
      public void print(){//覆寫抽象類的方法
      System.out.println("Hello World!");
 }   
   }
   //這個方法不受例項化物件的控制
   public static A getInstance(){
   return new B();
   }
}
public class TestDemo{
   public static void main(String args[]){
    //此時取得抽象類物件的時候完全不需要知道A有一個子類B
A a = A.getInstance();
a.print();
   }
}
這樣的設計在系統類庫之中會比較常見,目的:為使用者隱藏不需要知道的子類。
遺留問題:
首先看一段程式碼:
abstract class A {
   public A(){//2.父類構造方法
        this.print();//3.呼叫print()方法
   }
   public abstract void print();
}
class B extends A{
   private int num = 100;
   public B(int num){
      this.num = num;
   }
   public void print(){//4.呼叫覆寫後的方法
       System.out.println("num = "+num);//num還沒初始化,內容是其對應資料型別的預設值
   }
}
public class TestDemo{
   public static void main(String args[]){
       new B(30);//1、執行構造
   }
}
輸出結果是num = 0;
解決思路:在任何一個類的構造執行完之前,所有屬性的內容都是其對應資料型別的預設值,而子類構造執行之前一定先執行父類構造,那麼此時子類構造由於沒有執行,所以num就是0.
三、抽象類應用--模版設計(理解)
例如:現在有三類事物:
      機器人:充電、工作
 人:吃飯、工作、睡覺
 豬:吃飯、睡覺
要求可以實現以上的操作控制,即可以任意的控制人、機器人、豬的操作行為(吃、工作、睡覺)  
eg:
定義行為類:
abstract class Action{
   //定義三個全域性常量
   public static final int EAT = 1;
   public static final int SLEEP = 5;
   public static final int WORK = 7;
   public void command(int flag){
      switch(flag){
    case EAT:
   this.eat();
break;
    case SLEEP :
   this.sleep();
break;
    case WORK :
   this.work();
break;
case EAT+WORK :
   this.eat();
this.work();
break;
 }
   }
   public abstract void eat();
   public abstract void sleep();
   public abstract void work();
}
定義機器人的類:
class Robot extends Action{
   public void eat(){
      System.out.println("機器人補充能量!");
   }
   public void sleep(){
   }
   public void work(){
      System.out.println("機器人正在努力工作");
   }
}
定義人的類:
class Human extends Action{
   public void eat(){
      System.out.println("人類正在吃飯!");
   }
   public void sleep(){
     System.out.println("人類正在睡覺休息!");
   }
   public void work(){
      System.out.println("人為了夢想正在努力工作");
   }
}
定義豬的類:
class Pig extends Action{
   public void eat(){
      System.out.println("豬正在啃食槽!");
   }
   public void sleep(){
     System.out.println("豬在睡覺養膘!");
   }
   public void work(){     
   }
}


public class TestDemo{
   public static void main(String args[]){
        //執行fun()方法

        fun(new Robot());
fun(new Human());
fun(new Pig());
   }
   public static void fun(Action act){//建立Action類的物件act,可以使用Action的方法command。
        act.command(Action.EAT);//傳入Action類的常量
act.command(Action.SLEEP);
act.command(Action.work);
   }
}
這三個都屬於行為的子類,所以都可以通過行為來控制,這些不同的型別最終都在行為上成功的進行了抽象,即:如果要想使用行為操作,那麼就必須按照Action類的標準來實現子類。


總結:
1.如果你真的要使用類繼承的話,那麼就使用抽象類(20%的情況下可能這樣使用)。
2.抽象類強制規定了子類必須要做的事情,而且可以與抽象類的普通方法相配合
3.不管抽象類如何努力都有一個天生最大的問題:單繼承侷限。