1. 程式人生 > >JAVA 構造器,extends[繼承],implements[實現],Interface[介面],reflect[反射],clone[克隆],final,static,abstract[抽象]

JAVA 構造器,extends[繼承],implements[實現],Interface[介面],reflect[反射],clone[克隆],final,static,abstract[抽象]


構造器[建構函式]:

在java中如果使用者編寫類的時候沒有提供建構函式,那麼編譯器會自動提供一個預設建構函式.它會把所有的例項欄位設定為預設值:所有的數字變數初始化為0;所有的布林變數設定為false;所有物件變數設定為null;

PS:

只有在類中沒有其它構造器的時候,系統才會提供預設構造器.如果你希望使用者能能夠呼叫不帶引數的構造器,那麼你就必須自己實現一個.

extends[繼承]:

java中的繼承,和C++中是有差別的.比如JAVA不支援多重繼承。但是JAVA可以通過implements來實現額外的介面.

Example:

DogDeriveClass extends AnimalBaseClass

{

};

這樣DogDeriveClass就全盤繼承了AnimalBaseClass中的所有方法;但是沒有多重繼承,那麼如果還需要其它功能,那麼則可以通過implements關鍵字來實現需要用到的介面.

Example:

DogDeriveClass extends AnimalBaseClass

Implements Shout, Run

{

     void Shot()

     {

     // Do shout something;

     }

    void Run()

    {

    // Do run something;

    }

};

從上面程式碼可以看到,雖然JAVA不支援多重繼承,但是派生類可以通過實現介面的方式,來實現本身需要繼承過來的功能.

Implements[實現]:

Implements關鍵字在class宣告中使用,以指示所宣告的類提供了在implements關鍵字後面的名稱所指定的介面中所宣告的所有方法的實現。

介面中的欄位[變數]預設是public static final型別; //從介面的呼叫方式可以看出來. ImplementsInterface.MethedOfInterface();

介面中的方法不能是static,因為static不能被派生類重寫,因為如果介面和派生類中都有一個static同名方法,那麼根據static的呼叫方式可以看到

Interface.StaticMethed()即可呼叫,但是Interface中並沒有該方法的實現,只有在具體實現類中有實現,如果有兩個派生類都實現了同名的static方法,則該怎麼呼叫?

虛擬機器也不知道了!!所以不能這麼做.

Example:

public class UserSurfaceView extends SurfaceView 
implements Android.view.SurfaceHolder.Callback  
{

     @Override 

     public void surfaceChanged(SurfaceHolder holder, int format, int with, int heigh)

     {

     //TODO Auto-generated method stub

     }

    @Override

     public void surfaceCreated(SurfaceHolder holder)

     {

     //TODO Auto-generated method stub

     }

     @Override

     public void surfaceDestroyed(SurfaceHolder holder)

     {

     //TODO Auto-generated method stub

     }

};

UserSurfaceView類就要實現SurfaceHolder物件中的Callback介面中所宣告的所有方法的實現: surfaceChanged/surfaceCreated/surfaceDestroyed

從SDK上看到Android.view是包名,SurfaceHolder是一個public的interface, 而Callback就自然是public static interface[從呼叫方式即可看出來:Android.view.SurfaceHolder.Callback ]

Interface[介面]:

從上面implements關鍵字我們已經大概的瞭解到了關於java中介面的相關知識,下面看看介面的宣告:

Example:

public interface Android.view.SurfaceHolder.Callback 

{

         void surfaceChanged(SurfaceHolder holder, int format, int with, int heigh);

        void surfaceCreated(SurfaceHolder holder);

        void  surfaceDestroyed(SurfaceHolder holder);

};

由於介面中的方法宣告預設就是public的,因此不需要特意加上public修飾符.

reflect[反射]:

能夠分析類的能力的程式稱為反射器,JAVA中提供此功能的包是java.lang.reflect.它主要是針對工具構建者而不是應用程式設計師的.如果你只對編寫應用程式感興趣,而不想了解如何編寫供其它java程式設計師使用的工具,那麼就不要了解該機制.

java的反射機制主要提供了以下功能:

1.在執行時判斷任意一個物件所屬的類;

2.在執行時構造任意一個類的物件;

3.在執行時判斷任意一個類所具有的成員變數和方法[通過反射機制甚至可以呼叫private方法];

4.在執行時呼叫任意一個物件的方法;

java.lang.reflect包中包括下面幾個主要:

0.Class類,描述類相關資訊;

1.Field類,描述類的欄位;

2.Method類,描述類的方法;

3.Constructor類,描述類的構造器;

3.Array類,描述類的建立動態陣列的方法,該類中所有的方法都是靜態屬性;

下面我們開始介紹一些具體的用法:

A.Class類:

    在JAVA的Object類中聲明瞭若干個可以在所有的JAVA類中改寫的方法:

hashCode()/equals()/clone()/toString()/getClass()等,其中getClass()返回一個Class型別的物件.

    Class類和一般的類一樣繼承自Object, 其實體用於表達JAVA程式執行時的class和interface,以及enum, array, primitive, JAVA types和關鍵字void,當載入一個類時,或者當載入器[class loader]的defineClass()被JVM呼叫,便產生一個Class物件.

    Class是Reflection起源,針對任何你想檢視的Class(類),必須先給該類生成一個Class的物件,然後才能通過這個物件呼叫相應的反射API。

    JAVA提供了多種途徑來為一個Class類生成對應的Class物件:

    A,getClass(): Object類中的方法每個類都擁有該方法.

         Example:

         String str = "Test getClass()";

         Class cl = str.getClass();

    B,Class.getSuperclass(): Class類中的方法,返回該Class的父類的Class;

    C,Class.forName()靜態方法:作用同上;

    D,類名.Class: 作用同上;

    E,primitive wrapper classer的TYPE語法:

        基本型別包裝類的TYPE,Example, Integer.TYPE

        PS: TYPE的使用,只適合原生[基本]資料型別.

B.執行時生成instance

       要生成物件的實體,在反射機制中有兩種方式:

       1.針對不帶引數的構造器;

           Class類中的newInstance()實現該功能;

       2.針對帶引數的構造器;

           Constructor類中的newInstance()方法,實現該功能.首先準備一個Class[]作為Constructor的引數型別.然後呼叫該Class物件的getConstructor()得到一個專屬的Constructor物件,最後再準備一個Object[]作為Constructor物件裡的newInstance()的實參.

           Example:

           Class c = Class.forName("DynamicTest");

           Class[]  pType = new Class[]{double.class, int.class};

           Constructor ctor = c.getConstructor(pType);

           Object[] obj = new Object[] {new Double(3.14), new Integer(119)};

           Object object = ctor.newInstance(obj);

           System.out.println(object);

C. 執行時呼叫Method:

      首先必須通過Class[]作為getMethod(String name, Class[])方法的引數型別, 然後再通過Object[]存放變數,最後呼叫Method物件的invoke(Object obj, Object[])方法.

D.執行時呼叫Field內容:

      修改Field不需要引數和變數, 首先呼叫Class的getField()方法並制定Field名稱,獲得特定的Field物件後便可以直接呼叫Field的get(Object obj)和Set(Object obj, Object value)方法.       

克隆[clone]:

其實這個方法的引入,就是為了實現類似C++中深拷貝的功能.在C++中引數的傳遞有:傳值,傳地址,傳引用.

在JAVA中引數傳遞、=的賦值操作都是"引用傳遞[淺拷貝]",因此為了避免誤操作,在需要傳值的時候就不能進行傳引用.

PS:如果類成員變數有陣列或者複雜成員時需要進行深度克隆.淺拷貝只複製物件本身,並不複製該物件的引用、指標等成員所指向的地址.

       try{

        classObj = (classObject) super.clone(); // 通常情況下,這一行程式碼可以實現普通的克隆.

       }

       catch(CloneNotSupportedException e)

       {

            e.printStackTrace();

       }

        如果classObject類中包含了String name[]成員,那麼就需要進行深度克隆

        try{

        classObj = (classObject)super.clone();

        classObj.name = (String)name.clone();

        }

       catch(CloneNotSupportedException e)

       {

            e.printStackTrace();

       }


final:

一般處於設計和效率的考慮使用final,第一final類不被繼承、方法不被覆蓋.第二final方法會被編譯器在呼叫final的時候轉入內嵌機制大大提高執行效率.第三防止被修改;

final類不能被繼承,final類不能有子類,final類中的方法預設是final型別.

final方法不能被子類的方法覆蓋,但可以被繼承;

final成員變量表示常量,只能賦值一次,賦值後不能再改變;

final不能修飾構造器;

PS:父類的private方法是不能被子類方法覆蓋的,因為父類的private方法預設是final的;

static:

JAVA中的靜態欄位和方法在功能上和C++的靜態欄位與方法是相同的.表示屬於一個類而不是屬於此類的任何特定物件的變數和函式.

呼叫方式:

className.staticMethod();

只要這個類被載入,那麼JAVA虛擬機器就能根據類名在執行時的資料區的方法區內找到它們;

靜態欄位在記憶體中只有一個拷貝,JVM只為靜態欄位分配一次記憶體,在載入類的過程中完成對靜態欄位的記憶體分配;

abstract:

抽象類,具有一個或多個抽象方法的類必須被宣告為abstract.通常要儘可能的把通用欄位和非常抽象方法移到抽象超類中.

Object類:

Object類是JAVA中所有類的最終的祖先------每一個類都由他擴充套件而來.

Internal Class內部類:

內部類是定義在其它類內部的類,一般使用內部類有四個原因:

1.內部類物件能夠訪問建立它的物件的實現---包括那些私有資料;

2.內部類能夠隱藏起來,不為同一包中的其它類所見;

3.匿名內部類可以方便的定義執行時回撥;

4.使用內部類在編寫事件驅動的程式時用起來很方便;

PS:

本地內部類與匿名內部類的區別在於本地內部類有建構函式,而匿名內部類只能例項初始化。

Example:

      Thread thd = new Thread(

       new A(){//這裡就是一個匿名內部類

                     }

       )

Proxy[代理]:

通過使用代理可以在執行時建立實現一組給定介面的新類.

代理類具有:

指定介面所要求的所有方法;

Object類定義的所有方法(toString, equals等等);

因為我們不能在執行時給這些方法定義新的程式碼.你必須提供一個呼叫處理器.呼叫處理器是實現了InvocationHandler介面的任意類的物件.該介面只有一個方法:

Object invoke(Object proxy, Method method, Object[] args)

只要呼叫了代理物件上的任意一個方法,呼叫處理器的invoke方法就會被呼叫,帶著Method物件和原呼叫的引數.隨後呼叫處理器必須指出如何處理呼叫.

要建立一個代理物件,我們必須使用proxy類中的newProxyInstance方法,該方法有三個引數:

1>類載入器.

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

3>一個呼叫處理器;

如何定義處理器?

對結果代理物件能做些什麼?

答案要取決於我們要使用代理機制解決的問題.代理可以用於很多目的:

a.路由對遠端伺服器的方法呼叫;

b.在執行程式中把使用者介面事件和動作關聯起來;

c.為除錯目的跟蹤方法呼叫;

詳細參見:JAVA2核心技術卷1,P225