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