八,抽象類與接口


1.抽象類

1.1定義

包含號一個抽象方法的類稱爲抽象類.須要用abstract聲明. java

並非全部的類都是用來描繪對象的,若是一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。抽象類每每用來表徵咱們在對問題領域進行分析、 設計中得出的抽象概念,是對一系列看上去不一樣,可是本質上相同的具體概念的抽象,咱們不能把它們實例化(拿不出一個具體的東西)因此稱之爲抽象。 編程

須要注意的是抽象類不能直接實例化,但能夠聲明,要想使用抽象類,必須依靠子類,抽象類是必須被子類繼承的,並且被繼承的子類須要實現抽象類中的所有抽象方法. 設計模式

:抽象類必須被實現,因此不能用final修飾. app

示例: 編程語言

public abstract class AbstractClass //裏面至少有一個抽象方法
{
  public int t; //普通數據成員
   public abstract void method1(); //抽象方法,抽象類的子類在類中必須實現抽象類中的抽象方法
  public abstract void method2();
  public void method3(); //非抽象方法
  public int method4();
  publi int method4 (){
  …… //抽象類中能夠賦予非抽象方法方法的默認行爲,即方法的具體實現
  }

public void method3(){
  …… //抽象類中能夠賦予非抽象方法方法的默認行爲,即方法的具體實現
  }

}

1.2抽象方法

在面向對象編程語言中抽象方法指一些只有方法聲明,而沒有具體方法體的方法。抽象方法通常存在於抽象類或接口中。 函數

java中的抽象方法就是以abstract修飾的方法,這種方法只聲明返回的數據類型、方法名稱和所需的參數,沒有方法體,也就是說抽象方法只須要聲明而不須要實現。 學習

數學中的抽象是指抽取出同類數學對象的共同的、本質的屬性或特徵,捨棄其餘非本質的屬性或特徵的思惟過程。即把研究對象或問題中抽取數量關係或空間形式而捨棄其它屬性對其進行考察的思惟方法。 測試


1.3抽象類中的構造方法

抽象類中容許有構造方法,但構造方法是不能直接調用的,是交給子類去調用的,子類實例化過錯中,永遠是先調用父類的構造方法.抽象類中的構造函數是有做用的。子類繼承抽象類時,構造函數不會被覆蓋。 並且,在實例化子類對象時首先調用的是抽象類中的構造函數再調用子類中的. 所以,在抽象類中可使用構造函數封裝繼承子類公共的東西。 ui

2.接口(interface

2.1定義

接口是一個特殊的類,java中接口是由抽象方法和全局常量組成. this

接口也須要子類,不過子類再也不是繼承,而是實現接口,經過implements關鍵字完成.接口有多繼承的能力.

一個接口不能繼承一個抽象類,可是一個接口卻能夠同時繼承多個接口.

示例:

public interface Interface
{
  static final int i; //接口中不能有普通數據成員,只可以有靜態的不能被修改的數據成員,
                       //static表示全局,final表示不可修改,
                       //能夠不用static final 修飾,會隱式的聲明爲static和final
  

   public void method1(); //接口中的方法必定是抽象方法,因此不用abstract修飾
  

  public void method2(); //接口中不能賦予方法的默認行爲,即不能有方法的具體實現
}
  簡言之抽象類是一種功能不全的類,接口只是一個抽象方法聲明和靜態不能被修改的數據的集合,二者都不能被實例化。

  從某種意義上說,接口是一種特殊形式的抽象類,在java語言中抽象類表示的是一種繼承關係,一個類只能繼承繼承一個抽象類,而一個類卻能夠實現多個接口。在許多狀況下,接口確實能夠代替抽象類,若是你不須要刻意表達屬性上的繼承的話。

2.2示例

interface A{
	public void fun() ;
}
class B implements A{
	public void fun(){
		System.out.println("Hello") ;
	}
};
public class InterPolDemo01{
	public static void main(String args[]){
		A a = new B() ;	// 爲接口實例化
		a.fun() ;
	}
};
接口也能夠像抽象類那樣經過對象多態性進行對象的實例化操做.

3.引入抽象類和接口的目的

1、從類的層次結構上看,抽象類是在層次的頂端,但在實際的設計當中,通常來講抽象類應當是後面纔會出現。爲何?實際上抽象類的獲取有點像數學中的提取 公因式:ax+bxx就是抽象類,若是你沒有前面的式子,你怎麼知道x是否是公因式呢?在這點上,也符合人們認識世界的過程,先具體後抽象。所以在設計 過程當中若是你獲得大量的具體概念並從當中找到其共性時,這個共性的集合就是抽象類應當是沒錯的。
2
interface從表面上看,和抽象類很類似,但用法徹底不一樣。它的基本功能就是把一些絕不相關的類(概念)集合在一塊兒造成一個新的、可集中操做的 「新類」。我給學生的一個典型例子就是「司機」。誰能夠當司機?誰均可以,只要領取了駕照。因此我無論你是學生,白領、藍領仍是老闆,只要有駕照就是司 機。

interface DriverLicence {
Licence getLicence();
}

class StudentDriver extends Student implements DriverLicence {
}
class WhtieCollarEmployeeDriver extends WhtieCollarEmployee implements DriverLicence {
}
class BlueCollarEmployeeDriver extends BlueCollarEmployee implements DriverLicence {
}
class BossDriver extends Boss implements Driver {
}
當我定義了「汽車」類後,我就能夠指定「司機」了。

class Car {
setDriver(DriverLicence driver);
}
這時候, Car的對象並不關心這個司機究竟是幹什麼的,他們的惟一共同點是領取了駕照(都實現了 DriverLicence接口)。這個,應當是接口最強大的地方也是抽象類沒法比擬的。
總結:抽象類是提取具體類的公因式,而接口是爲了將一些不相關的類「雜湊」成一個共同的羣體。一般咱們平時養成良好的習慣就是多用接口,畢竟 java是單繼承。


4.抽象類和接口的區別

4.1適配器設計模式

正常狀況下,一個接口的子類要實現所有的抽象方法.但實際中多是根據須要選擇性的覆寫,用一個類先將接口實現,全部的抽象方法都是空覆寫,而後繼承此類,這個類使用抽象類,由於抽象類也不能直接使用.

interface Window{
	public void open() ;	// 打開窗口
	public void close() ;	// 關閉窗口
	public void icon() ;	// 最小化
	public void unicon() ;	// 最大化
}
abstract class WindowAdapter implements Window{
	public void open(){}
	public void close(){}
	public void icon(){}
	public void unicon(){}
};
class MyWindow extends WindowAdapter{
	public void open(){
		System.out.println("打開窗口!") ;
	}
};
public class AdpaterDemo{
	public static void main(String args[]){
		Window win = new MyWindow() ;
		win.open() ;
	}
}
這樣就實現了部分覆寫的目的 ,將一個類的接口轉換成客戶但願的另一個接口 .Adapter模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠在一塊兒工做 .

優勢
①經過適配器,客戶端能夠調用同一接口,於是對客戶端來講是透明的.這樣作更簡單、更直接、更緊湊.
②複用了現存的類,解決了現存類和複用環境要求不一致的問題.
③將目標類和適配者類解耦,經過引入一個適配器類重用現有的適配者類,而無需修改原有代碼.
④一個對象適配器能夠把多個不一樣的適配者類適配到同一個目標,也就是說,同一個適配器能夠把適配者類和它的子類都適配到目標接口.
缺點
①對於對象適配器來講,更換適配器的實現過程比較複雜.
適用場景: 系統須要使用現有的類,而這些類的接口不符合系統的接口. 或者舊的系統開發的類已經實現了一些功能,可是客戶端卻只能以另外接口的形式訪問,但咱們不但願手動更改原有類的時候. 還有使用第三方組件,組件接口定義和本身定義的不一樣,不但願修改本身的接口,可是要使用第三方組件接口的功能.
應用舉例:使用過ADO.NET的開發人員應該都用過DataAdapter,它就是用做DataSet和數據源之間的適配器.DataAdapter經過映射FillUpdate來提供這一適配器.

備註:ADO.NET的名稱起源於ADOActiveX Data Objects,是一個COM組件庫,用於在以往的Microsoft技術中訪問數據.之因此使用ADO.NET名稱,是由於Microsoft但願代表,這是在NET編程環境中優先使用的數據訪問接口.
GoF的設計模式中,對適配器模式講了兩種類型,類適配器模式對象適配器模式.因爲類適配器模式經過多重繼承對一個接口與另外一個接口進行匹配,C#java等語言都不支持多重繼承,於是這裏只是介紹對象適配器.


4.2 工廠設計模式

代碼示例:

interface Fruit{
	public void eat() ;
}
class Apple implements Fruit{
	public void eat(){
		System.out.println("吃蘋果...") ;
	}
};
class Orange implements Fruit{
	public void eat(){
		System.out.println("吃橘子...") ;
	}
};
class Factory{	// 工廠類
	public static Fruit getFruit(String className){
		Fruit f = null ;
		if("apple".equals(className)){
			f = new Apple() ;
		}
		if("orange".equals(className)){
			f = new Orange() ;
		}
		return f ;
	}
};
public class InterDemo{
	public static void main(String args[]){
		Fruit f = Factory.getFruit(args[0]) ;
		if(f!=null){
			f.eat() ;
		}
	}
}
全部接口的實例化都經過工廠類取得 ,客戶端調用的時候傳入的名稱不一樣 ,完成的功能不一樣 .

工廠模式主要用一下幾種形態:簡單工廠(Simple Factory,工廠方法(Factory Method,抽象工廠(Abstract Factory.(詳細見設計模式的博文)


4.3 代理設計模式

示例:

interface Give{
	public void giveMoney() ;
}
class RealGive implements Give{
	public void giveMoney(){
		System.out.println("把錢還給我。。。。。") ;
	}
};
class ProxyGive implements Give{	// 代理公司
	private Give give = null ;
	public ProxyGive(Give give){
		this.give = give ;
	}
	public void before(){
		System.out.println("準備:小刀、繩索、鋼筋、鋼據、手槍、毒品") ;
	}
	public void giveMoney(){
		this.before() ;
		this.give.giveMoney() ;	// 表明真正的討債者完成討債的操做
		this.after() ;
	}
	public void after(){
		System.out.println("銷燬全部罪證") ;
	}
};
public class ProxyDemo{
	public static void main(String args[]){
		Give give = new ProxyGive(new RealGive()) ;
		give.giveMoney() ;
	}
};
代理模式對外部提供統一的接口方法 ,而代理類在接口中實現對真實類的附加操做行爲 ,從而不影響外部調用狀況下 ,進行系統擴展 .即修改真實角色的操做的時候 ,儘可能不要修改他 ,而是在外部「包」一層進行附加行爲 ,即代理類 .

例如:接口A有一個接口方法operator(),真實角色RealA實現接口A,則必須實現接口方法operator().客戶端Client調用接口A的接方法operator().新需求須要修改RealA中的operator()的操做行爲.但修改RealA就會影響原有系統的穩定性,還要從新測試.這是就須要代理類實現附加行爲操做.建立代理ProxyA實現接口A,並將真實對象RealA注入進來.ProxyA實現接口方法operator(),另外還能夠增長附加行爲,而後調用真實對象的operator().從而達到了「對修改關閉,對擴展開放,保證了系統的穩定性.客戶端Client調用還是接口A的接口方法operator(),只不過實例變爲了ProxyA類了而已.也就是說代理模式實現了ocp原則.

備註:ocp原則即開閉原則(Open Closed Principle)是Java最基礎的設計原則,有助於創建一個穩定的、靈活的系統.一個軟件實體如類、模塊和函數應該對擴展開放,對修改關閉.

4.4抽象類與接口的區別

經過對比可知,若是二者均可以使用的話,優先使用接口,由於它能夠避免單繼承的侷限.

抽象類中容許包含接口:

abstract class A{
	public abstract void fun() ;
	interface B{	// 內部接口 
		public void print() ;
	}
};
class X extends A{
	public void fun(){
		System.out.println("****************") ;
	}
	class Y implements B{
		public void print(){
			System.out.println("===================") ;
		}
	};
};
public class TestDemo01{
	public static void main(String args[]){
		A a = new X() ;
		a.fun() ;
		A.B b = new X().new Y() ;
		b.print() ;
	}
};
接口中容許包含抽象類 :
interface A{
	public void fun() ;
	abstract class B{	// 內部抽象類
		public abstract void print() ;
	}
};
class X implements A{
	public void fun(){
		System.out.println("****************") ;
	}
	class Y extends B{
		public void print(){
			System.out.println("===================") ;
		}
	};
};
public class TestDemo02{
	public static void main(String args[]){
		A a = new X() ;
		a.fun() ;
		A.B b = new X().new Y() ;
		b.print() ;
	}
};



20150413


JAVA學習筆記系列

--------------------------------------------

                    聯繫方式

--------------------------------------------

        Weibo: ARESXIONG

        E-Mail: aresxdy@gmail.com

------------------------------------------------
相關文章
相關標籤/搜索