1. 程式人生 > >java 面向物件 上

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類的靜態初始化快...最後再執行該類的靜態初始化塊。

靜態初始化塊只會在類被建立的時候使用,而不會每次建立例項的時候使用。