java物件導向--對象初始化,java物件導向初始化
重載(Overload)是指在一個類裡面,多個方法的名字相同,而參數列表(參數的類型、個數和順序)不同。傳回值類型和修飾符與重載無關。解決相同意義的行為使用不同名字的問題。
構造器最大的作用就是在建立對象時執行初始化。
預設構造器又名無參構造器,作用是建立一個預設對象。如果類中沒有任何構造器,則編譯器會自動建立一個預設構造器。如果已經自行定義了任意一個構造器,編譯器就不會自動建立無參構造器。
所有執行個體共用一份方法,編譯器會把當前對象的引用作為第一個參數傳入方法內部,以區分不同的調用對象。
this:在方法內部使用,this表示對“調用方法的那個對象”的引用。最大的作用就是讓類中的一個方法,訪問該類的另一個方法或屬性。
static方法是沒有this的方法,所以靜態成員不能訪問非靜態成員。
static關鍵字:修飾的成員表明它是屬於類共有的,既可以通過類訪問,也可以通過執行個體訪問。
在方法內部訪問同一個類的成員,不需要使用this。
如果參數變數和成員變數同名時,可以用this.field=field加以區分。
在構造器中調用構造器:this可以指代重載的其他構造器方法以減少代碼重複。注意此時this(arg)必須作為構造器中的第一句代碼。
public class Teacher { private String name; private int age; public Teacher(String name,int age ){ this(name); this.age=age; } public Teacher(String name){ this.name = name; }}
待用資料、成員變數及構造器的初始化順序
無繼承時:
假設有個名為Dog的類,建立過程如下:
1.當首次建立類型為Dog的對象時(構造器可以看成靜態方法),或者Dog類的靜態方法/靜態域首次被訪問時,Java解譯器必須尋找類路徑,以定位Dog類的編譯代碼(在Dog.class檔案中)。
2.然後載入Dog.class(這將建立一個Class對象),執行有關靜態初始化的動作。因此,靜態初始化只在Class對象首次載入的時候進行一次。 靜態變數和靜態初始塊化塊按定義的順序進行初始化。
3.當用new Dog()建立對象的時候,首先將在堆上為Dog對象分配足夠的儲存空間。
4.這Block Storage空間會被清零,這就自動地將Dog中的所有基本類型資料設定成了預設值(對數字來說就是0,對布爾型和字元型也相同),而引用則被置成了null。 (預設初始化)
5.執行所有出現於成員變數定義處的初始化動作。(按定義的先後順序進行顯示初始化,包括成員變數和初始化塊)
6.執行構造器。
7.物件建構完畢,將地址賦給參考型別變數。
有繼承時:
假設有個名為Golden的類,繼承自Dog,Dog又繼承自Animal,初始化過程如下:
1.當首次建立類型為Golden的對象時,Java載入器尋找Golden類的編譯代碼(在Golden.class檔案中)。
2.Java載入器會載入Golden.class檔案,同時根據Golden.class(extends關鍵字)載入其基類Dog.class檔案,再根據Dog.class載入根基類Animal.class檔案。然後從根基類Animal到基類Dog再到子類Golden依次執行待用資料的初始化。 (子類的待用資料在父類的成員變數之前初始化)
3.當你用new Golden ()建立對象的時候,首先將在堆上為Golden對象(包括本類Golden、基類Dog和根基類Animal中的所有成員變數)分配足夠的儲存空間。由於子類的構造器不能訪問父類的private成員,所以必須利用super關鍵字來初始化這部分成員變數。
4.這Block Storage空間會被初始化預設值即二進位的零。Golden中的所有基本類型資料(包括其基類Dog和Animal中的)設定成了預設值(對數字來說就是0,對布爾型和字元型也相同),而引用(包括其基類Dog和Animal中的)則被置成了null。也就是說在執行任何初始化代碼之前,所有執行個體變數都已設定完預設的初值。
5.執行根基類Animal中所有成員變數的初始化動作。
6.執行基根類Animal構造器。
7.執行基類Dog中所有成員變數的初始化動作。
8.執行基類Dog構造器。
9.執行匯出類Golden中所有成員變數的初始化動作。
10.執行匯出類Golden構造器。
簡單來說,就是從子類到基類依次載入類的class檔案,然後從根基類到子類依次進行待用資料的初始化。再為對象分配儲存空間,在儲存空間清零後,依次從父類到子類進行執行個體初始化(包括成員變數初始化,調用構造器2步)。
Java在開發人員沒有定義別的super語句時會自動在子類的構造器中插入對父類構造器的調用,該調用並不是簡單地執行父類建構函式,具體順序如下(省略類初始化過程):
1、進入當前類的構造方法,調用super()(會被編譯器改名為<init>,不執行別的代碼)直接進入父類構造方法,並遞迴到java.lang.Object類構造方法。
2、執行java.lang.Object類的初始化,順序為先初始化成員變數/初始化塊(按照定義順序),再調用構造方法(super部分不再執行)進行初始化。
3、運用步驟2的方法初始化java.lang.Object類的直接子類,並遞迴這個過程到當前類。
注意:
對象只能通過new constructor()的方式建立,所以編譯器在程式員沒有編寫構造器時會提供預設的無參構造器。Constructors are meant for initializing the members of objects.
類的載入發生在:new 對象時,訪問類的待用資料時,main方法所在的類在運行java應用時。而在類被載入時就會初始化待用資料。
對象會取得所有執行個體變數所需的空間,包括一路繼承下來的東西。
在建立對象時,所有父類的建構函式都會被執行:建構函式在執行的過程中,第一件事是調用它父類的建構函式(編譯器通過super調用或開發人員自己調用有參數的父類建構函式),直到連鎖反應到Object這個類為止,即“建構函式鏈”。
建立對象過程中,子類對象可能訪問從父類繼承下來的資料,所以super()必須是建構函式的第一個語句,父類建構函式必須在子類建構函式之前結束。
this(..)指代當前類的其他建構函式,也必須是建構函式中的第一句語句,所以super()和this()只能二選一。
每個對象除了儲存類的執行個體變數之外,還儲存著實際類資訊的引用,存放類資訊的記憶體區,在Java中稱為方法區。
虛方法表,就是在類載入的時候,為每個類建立一個表,這個表包括該類的對象所有動態綁定的方法及其地址,包括父類的方法,但一個方法只有一條記錄,子類重寫了父類方法後只會保留子類的。
class Glyph { void draw() { System.out.println("Glyph.draw()"); }; Glyph() { System.out.println("Glyph() before draw()"); draw(); // 調用重寫了的子類型方法 System.out.println("Glyph() after draw()"); }}class RoundGlyph extends Glyph { private int radius = 1; RoundGlyph(int r) { radius = r; System.out.println("RoundGlyph.RoundGlyph(), radius = " + radius); } void draw() { System.out.println("RoundGlyph.draw(), radius = " + radius); }}public class PolyConstructors { public static void main(String[] args) { new RoundGlyph(5); }}/*Glyph() before draw()RoundGlyph.draw(), radius = 0Glyph() after draw()RoundGlyph.RoundGlyph(), radius = 5*/