java 面向物件 上
static修飾的成員不能直接訪問沒有static修飾的成員
有static修飾的成員屬於類本身,沒有static修飾的成員屬於該類的例項
static修飾的方法和成員變數既可以通過類來呼叫,也可以通過例項來呼叫。沒有static修飾,只能通過例項來呼叫。
構造器不能定義返回值型別,也不能使用void,因為編譯器會把這個當成方法來處理。實際上,構造器是有返回值的,只不過返回值是隱式的,它返回的是該類的例項。
與之前寫的陣列型別類似,類也是一種引用資料型別,引起定義的型別的變數實際上是引用,它被存在棧記憶體中,而實際的物件例項被存在堆記憶體中。
this有兩個作用:
引用構造器中正在初始化的物件
this的最大作用就是讓類中的一個方法訪問該類中的另外的方法
//如果不適用this,需要建立該類的物件才能呼叫另一個方法
public class Person(){
public void eat(){
}
public void sleep(){
Person p=new Person();
p.eat();
}
}
public class Person{ public void eat(){ } public void sleep(){ this.eat(); } }
java允許一個物件的成員直接呼叫另一個成員,可以省略this字首。
對於static修飾的方法而言,可以使用類來直接呼叫這個方法,如果使用this,那麼它並不知道指向哪一個物件。所以,靜態成員不能訪問非靜態成員。
Java語言的方法所表現的屬性如下:
方法不能獨立定義,方法只能在類體中定義。
從邏輯意義上看,方法要麼屬於該類本身,要麼屬於該類的一個物件
永遠不能獨立執行方法,執行方法必須有類或者物件的呼叫
沒有static修飾的方法只能使用物件來呼叫,不能使用類來呼叫\
java將實際引數值的副本(複製品)傳入方法中,而引數本身不受影響
public class TestPrimitiveTransfer
{
public static void swap(int a , int b)
{
int tmp = a;
a = b;
b = tmp;
System.out.println("swap中的a,b"+a+" "+b);
}
public static void main(String[] args)
{
int a = 6;
int b = 9;
swap(a , b);
System.out.println("交換後的a,b"+a+" "+b);
}
}
但在傳遞引用型別時,通過呼叫函式,會把地址傳給swap
public class TestReferenceTransfer
{
public static void swap(DataWrap dw)
{
int tmp = dw.a;
dw.a = dw.b;
dw.b = tmp;
}
public static void main(String[] args)
{
DataWrap dw = new DataWrap();
dw.a = 6;
dw.b = 9;
swap(dw);
}
}
區域性變數會覆蓋掉同名的成員變數,如果想使用被覆蓋的成員變數可以用this或類作為呼叫者來訪問成員變數
形參個數可變的方法:
void test(String ... books){
for(String i:books);
}
構造器可以呼叫另一個構造器中的程式碼,可以使用this關鍵字來呼叫相應的構造器。例如一個有三個引數的構造器,可以呼叫有兩個引數的構造器。通過 this(name,id),另一個變數在自己的構造器中來實現的方法來實現。
類的繼承
每個類只能有一個直接的父類,實際上,類可以有無限個間接的父類
子類是對父類的擴充套件
class Fruit extends Plant{}
class Apple extends Fruit{}
定義一個類時並未顯示指定這個類的直接父類,則這個類預設擴充套件java.lang.Object類。因此java.lang.Object是所有類的父類,要麼是直接父類,要麼是間接父類。
子類可以重寫父類的方法(override)要遵循“兩同兩小一大”。
方法名相同,引數列表相同
子類返回值的型別應比父類的小或者相等,子類方法宣告丟擲的異常類應比父類小或相等
子類的訪問許可權應該比父類大或者相等
如果父類的一個方法具有private訪問許可權,因此對子類是隱藏的,所以子類無法對他進行重寫
過載(overload)重寫(override)的區別:
過載主要發生在同一個類中多個同名的方法中,而過載發生在子類和父類的方法中。當然,子類方法和父類方法可能發生過載,
因為子類會獲得父類的方法,所以...
super用於限定該物件呼叫它從父類繼承得到的例項變數或方法,super和this一樣不能出現在static修飾的方法中。
在建立子類物件時,系統不僅會為該類中定義的例項變數分配記憶體,也會為從父類繼承得到的例項變數分配記憶體。
class Parent{
public String tag="MIT";
}
class Derived extends Parent{
private String tag="TsingHua";
}
public class Test{
public static void main(String[] args) {
Derived d=new Derived();
//程式不能訪問d的私有變數,所以會引發編譯錯誤
//System.out.println(d.tag);
//將d變數顯示地向上轉型為Parent後,可以訪問
System.out.println((Parnet)d.tag);
}
}
子類可以呼叫父類的構造器,使用方法和this很像,super也必須放在第一行,區別是super呼叫的是父類的構造器,this呼叫的是同一個類的構造器。不管是否使用super呼叫來執行父類構造器的初始化程式碼,子類總會呼叫父類構造器一次。
當呼叫子類構造器時,父類構造器總會在子類構造器之前執行,不進如此,父類構造器還會上溯執行其父類構造器....所以最先執行的總是java.lang.Object 類的構造器
多型
編譯時型別和執行時型別不同,就稱為多型(Polymorphism)
允許把子類物件直接賦給一個父類引用變數,無須任何型別轉換,或者稱為向上型別(upcasting)
與方法不同的是,物件的例項變數不具備多型性
引用變數在編譯階段只能呼叫編譯型別所具有的方法,但執行時執行它執行時型別所具有的方法。
型別轉換:
數值型別和布林型別不能進行型別轉換
引用型別之間的轉換隻能在有繼承關係的兩個型別之間進行。如果把父類轉換成子類,則這個物件必須是子類例項才行(編譯時為父類型別,執行時為子類型別)否則將引發ClassCastException。
當把子類賦值給父類引用變數時,被稱為向上轉型(upcasting),這種轉型總是成功的
在進行強制型別轉換之前,先用instanceof可以判斷能否成功轉換,避免了異常。instanceof用於判斷前面的物件是否是後面的類,子類,實現類的例項。
初始化塊在建立物件時隱式執行,而且在構造器之前,一個類只能定義兩個。
用法:如果一段初始化程式碼對所有物件相同,且無需接受任何引數,就可以放在初始程式碼塊中。
建立物件時,不僅會執行該類的初始化塊和構造器,而且系統會一直追溯到java.lang.Object類,先執行java.lang.Object類的初始化程式碼塊,然後再執行java.lang.Object的構造器,然後再向下執行。
當初始化塊使用static修飾符,則這個初始化塊就變成了靜態初始化塊。普通初始化塊負責對物件進行初始化,類初始化塊負責對類進行初始化。將在類被建立的時候執行靜態初始化塊,而不是在建立物件的時候執行。不能訪問非靜態成員。與普通初始化塊類似,在類初始化階段,需要一直上溯到java.lang.Object類,先執行java,lang.Object類的靜態初始化快...最後再執行該類的靜態初始化塊。
靜態初始化塊只會在類被建立的時候使用,而不會每次建立例項的時候使用。