1. 程式人生 > >Java的介面與內部類

Java的介面與內部類

介面:主要用於描述類具有什麼功能,而不是給出每個功能的具體實現。

一個類可以實現一個或多個介面,並在需要介面的地方,隨時使用實現了相應的介面的物件。

克隆物件(深拷貝):指建立一個新物件,且新物件的狀態與原始物件的狀態相同

當對克隆的新物件進行修改時,不會影響原始物件的狀態。

內部類機制:內部類定義在另一個類的內部,其中的方法可以訪問包含它們的外部類的域,主要用於設計具有相互協作關係的類集合。

一、介面

在Java程式設計語言中,介面不是類,而是對類的一組需求描述,這些類要遵從介面描述的統一格式進行定義。

1>介面中的所有方法自動地屬於public,因此,在介面中宣告方法時,不必提供關鍵字public。

2>介面中可以定義常量,不能含有例項域,也不能在介面中實現方法。

3>類實現介面的步驟:

a>將類宣告為實現給定的介面。  關鍵字  implements

b>對介面中的所有方法進行定義。

注:

i>在介面宣告中,方法不需要宣告為public,因為在介面中的所有方法都自動地是public。不過,在實現介面時,必須把方法宣告為public,否則,編譯器將認為訪問屬性為包預設,即類的預設訪問屬性,之後編譯器就會給出試圖提供更弱的訪問許可權的警告資訊。

ii>如果需要呼叫底層的排序服務必須讓它實現Comparable介面的compareTo方法。

例如:使用Arrays.sort()方法對陣列進行排序,本質上必須對兩個物件進行比較,而比較的方式就是通過呼叫Comparable介面的compareTo方法。所以需要實現Comparable介面,如果直接建立compareTo方法,而不繼承介面的話,Java也無法呼叫。

( 1 )介面的特性

1>介面不是類,不能使用new運算子例項化一個介面。

2>不能構造介面的物件,卻能宣告介面的變數,但是介面變數必須引用實現了介面的類物件。

3>如同使用instanceof檢查一個物件是否屬於某個特定類一樣,也可以使用instance檢查一個物件是否實現了某個特定的介面。

4>介面可以被擴充套件,使用extends關鍵字類擴充套件某個介面。

5>介面中不能包含例項域或靜態方法,但卻可以包含常量。

6>介面中的方法都自動被設定為public,介面中的域將被自動設為public static final。

7>每個類只能擁有一個超類,但卻可以實現多個介面。

( 2 )介面與抽象類

Java不支援多繼承,因為多繼承會讓語言本身變得非常複雜,效率也會降低。

介面可以提供多重繼承,同時能避免多重繼承的複雜性和低效性。

二、物件克隆

當拷貝一個變數時,原始變數與拷貝變數引用同一個物件,改變一個變數所引用的物件將會對另一個變數產生影響。

使用clone方法可以建立一個物件的新的copy,最初狀態與原來的變數引用的物件一樣,而且可以各自改變自己的狀態。

1>clone方法時Object類的一個protected方法,使用者編寫的程式碼中不能直接呼叫。

2>預設的克隆操作是淺拷貝,資料域是數值或基本型別,沒有問題,但是如果包含子物件的引用,拷貝的結果會使兩個域引用同一個子物件。

因此需要重新定義clone方法,以便實現克隆子物件的深拷貝。

重新定義,類必須:

a>實現Cloneable介面;

b>使用public訪問修飾符重新定義clone方法。

注:

i>在這裡Cloneable介面的出現與介面的正常使用沒有任何關係,尤其是,它並沒有指定clone方法。該介面在這裡是作為一個標記,表明類設計者要進行克隆處理。如果不繼承該介面,就會產生一個已檢查異常。

ii>標記介面沒有方法,使用它的唯一目的是可以用instanceof進行型別檢查。

iii>只要在clone中含有沒有實現Cloneable介面的物件,Object類的clone方法就會丟擲一個CloneNot-SupportException異常。

iv>必須謹慎地實現子類的克隆,而且克隆並不像人們想象的普遍。在標準類庫中,只有不到5%的類實現了clone。

三、介面與回撥

回撥是一種常見的程式設計模式,在這種模式中,可以指出某個特定事件發生時應該採取的動作。

例如:

package com.interfaces;

/**
   @version 1.00 2000-04-13
   @author Cay Horstmann
*/

import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer; 
// to resolve conflict with java.util.Timer

public class TimerTest
{  
   public static void main(String[] args)
   {  
      ActionListener listener = new TimePrinter();

      // construct a timer that calls the listener
      // once every 10 seconds
      Timer t = new Timer(10000, listener);
      t.start();

      JOptionPane.showMessageDialog(null, "Quit program?");
      System.exit(0);
   }
}

class TimePrinter implements ActionListener
{  
   public void actionPerformed(ActionEvent event)
   {  
      Date now = new Date();
      System.out.println("At the tone, the time is " + now);
      Toolkit.getDefaultToolkit().beep();
   }
}

四、內部類

內部類:定義在另一個類中的類。

使用內部類的原因:

1>內部類方法可以訪問該類定義所在的作用域中的資料,包括私有的資料。

2>內部類可以對同一個包中的其他類隱藏起來。

3>當想定義一個回撥函式且不想編寫大量程式碼時,使用匿名內部類比較便捷。

( 1 )使用內部類訪問物件狀態

內部類即可以訪問自身的資料域,也可以訪問建立它的外圍類物件的資料域。(在呼叫內部類的建構函式時,隱式的將外圍類的引用作為傳遞)

( 2 )匿名內部類

建立一個實現介面的類的新物件,需要實現介面中的方法定義在括號{}內。

語法格式為:

new SuperType(construction parameters){
			inner class methods and data
		}
其中SuperType是介面,在{}內實現相應的方法。這樣內部類就實現了這個介面。

SuperType也可以是一個類,於是內部類就擴充套件它。

( 3 )靜態內部類

有時候,使用內部類只是為了把一個類隱藏在另一個類的內部,並不需要內部類引用外圍類物件。

為此,可以將內部類宣告為static,以便取消產生的引用。

( 4 )代理proxy

Java SE1.3新增加的特性。利用代理可以在執行時建立一個實現了一組給定介面的新類。這種功能只有在編譯時無法確定需要實現哪個介面時才有必要使用。

對於應用程式設計人員來說,遇見這種情況的機會很少,但是對於系統程式設計人員來說,代理帶來靈活性卻十分重要。

1>代理類可以在執行時建立全新的類,這樣代理類能夠實現指定的介面,而且具有下列方法:

a>指定介面所需要的全部方法。

b>Object類中的全部方法。

2>不能再執行時定義這些方法的新程式碼,而是要提供一個呼叫處理器。呼叫處理器是實現了InvocationHandler介面的類物件,介面中只有一個方法:Object invoke(Object proxy,Method method,Object[] args)

3>無論何時呼叫代理物件的方法,呼叫處理器的invoke方法都會被呼叫,並向其傳遞Method物件和原始的呼叫引數。呼叫處理器必須給出處理呼叫的方式。

建立代理物件,需要使用Proxy類的newProxyInstance方法,有三個引數:

a>一個類載入器

b>一個Class物件陣列,每個元素都是需要實現介面

c>一個呼叫處理器

4>代理類的特性

a>代理類在程式執行過程中建立的,一旦,就變成了常規類,與虛擬機器中的任何其他類沒有什麼區別。

b>所有的代理類都擴充套件於Proxy類,一個代理類只有一個例項域------呼叫處理器,它定義在Proxy的超類中。

為了履行處理物件的職責,所需要的任何附加資料都必須儲存在呼叫處理器中。

注:就目前而言,對於代理的部分感覺不理解,目前不常使用,所以暫且擱置,以後再詳細瞭解。