1. 程式人生 > >Java中通過this關鍵字呼叫構造方法的一些理解

Java中通過this關鍵字呼叫構造方法的一些理解

 

學習java時,理解的this關鍵字的實質是用來指向當前物件的一個指標。按照之前所學,理解它有以下三種用法加一個性質。

1.在構造方法中使用this

       關鍵字this可以出現在類的構造方法中,代表使用該構造方法所建立的物件。

public class Tom {
	int leg;
	
	Tom(int n) {
		this.cry();	//可以省略this,將this.cry();寫成cry();
		leg = n;
		this.cry();
	}
	
	void cry() {
		System.out.println("I'm Tom,I have " + leg +" legs");
	}

	public static void main(String[] args) {
		Tom cat = new Tom(4);  //當呼叫構造方法Tom時,其中的this物件就是cat
	}

}

2.在例項方法中使用this

       關鍵字this可以出現在類的例項方法中,代表使用使用該方法的當前物件。

       例項方法中可以利用this操作成員變數和成員方法,預設格式如下:

                                                                this.成員變數

                                                                this.方法

public class Tom {
	int leg;
	
	void evolution() {
		this.leg = 2;
		this.cry();
	}
	
	void cry() {
		System.out.println("I'm Tom,I have " + leg +" legs");
	}
	
	public static void main(String[] args) {
		Tom cat = new Tom();
		cat.leg = 4;
		cat.cry();
		cat.evolution(); //物件呼叫本方法時,修改了leg並呼叫類cry()方法
	}

}

3.區分成員變數和區域性變數

       如果在方法內區域性變數的命名與例項變數的命名相同,根據內部遮蔽外部的原則,例項變數在這個方法內暫時失效。這是如果想在該方法中使用例項變數,則需要在變數名前顯示的加上"this.",用來指明此變數是例項變數。預設格式如下(前者指示的是例項變數,後者指示的是區域性變數):

                                                              this.變數名= 變數名;

public class Tom {
	int leg;
	
	void setleg(int leg){
		this.leg = leg; //此處利用this區分了例項變數與區域性變數。
	}
	
	void cry() {
		System.out.println("I'm Tom,I have " + leg +" legs");
	}
	
	public static void main(String[] args) {
		Tom cat = new Tom();
		cat.setleg(4);
		cat.cry();
	}

}

4.類方法中不能使用this

       類方法(或有static修飾的靜態方法)中不能使用this關鍵字。因為這些方法是靜態的,常駐記憶體。當程式執行,為這些方法在記憶體中開闢儲存空間的時候,可能還沒有任何物件誕生。this關鍵字也就失去了意義。

一直以來,我都以為this的作用都較為基礎的止步於此。但在今天學習資料結構的過程中,我看到了這樣的程式碼。

public class SeqList<T> implements LList<T> {

        private Object [] element; //物件陣列
        private int len;           //順序表長度
	
	/**初始化順序表*/
	public SeqList(int size) {//size:順序表大小
		element = new Object[size];
		this.len = 0;
	}
	
	/**預設初始化順序表*/
	public SeqList(){
		this(64); //this.SeqList(size);
	}

 }

public class SeqListTest {

    public static void main(String[] args) {

        SeqList<Integer> sList = new SeqList<Integer>();

    }

}
    

在第二個構造方法中,可見 this(64); 這樣的語句。

這是JDK1.7以上新支援的功能。但初見時我並不理解這樣的語法,因為this語句在我的印象中只是用來指示當前物件的一個關鍵字。單純的指示當前物件,如果在例項化執行構造方法的同時又呼叫另一個構造方法,是否會生成一個新的物件?然而結果又是顯而易見的——只有一個物件生成,並具有設想中應該有的和內容。

那麼這樣的語法的底層又是怎樣去實現的呢?這讓我陷入了疑惑。

思索良久,看了一些別人的理解和想法,再利用一些小小的測試程式碼。我將我對這個問題的一些設想寫在這裡。

話不多說,先來複習一下構造方法執行時底層發生了什麼。

1.構造方法入棧。在堆區為物件開闢儲存空間,併為例項變數賦預設值。

2.執行構造程式碼塊(靜態或動態)、例項變數賦值賦值語句。在堆區為例項變數初始化。

3.執行構造方法剩餘語句,修改堆區例項變數的初始值。

4.構造方法彈棧。

以上是一般構造方法執行時的底層表現,那麼按我的理解敘述一下以下程式碼在執行時的底層表現。

public class Tom {
    int head = 0;
    int leg;

    public Tom(int leg){
        this.leg = leg;
    }
    
    public Tom() {
        this(6);
        this.head = 3; 
    }
    
    public static void main(String[] args) {
        Tom cat = new Tom();               
        System.out.println("I'm Tom,I have " + cat.head +" head");
        System.out.println("I'm Tom,I have " + cat.leg +" legs");
    }

}

記憶體圖

記憶體圖分析

0. JVM生成位元組碼並載入到方法區blablabla...

1.main方法入棧;

2.無參構造方法Tom入棧。JVM在堆區開闢儲存空間,為例項變數head、leg賦初值0;

3.執行構造程式碼塊(這裡沒有),以及初始化語句。為head賦初值0;

4.執行構造方法體。並在第一句通過this轉入帶參構造方法Tom(int leg),Tom(int leg)入棧;

5.因為this指向當前物件,所以執行構造器為leg賦值6,Tom(int leg)出棧。返回無參構造方法斷點處繼續執行,為head賦值3,Tom()出棧;

6.繼續執行main方法,直至程式結束,main出棧。

可見,this(引數)這種語法可以完成對構造方法的呼叫~

這裡附上構造方法中使用this呼叫另一構造方法的相關規則:

(1)假如在一個構造方法中使用了this語句,那麼它必須作為構造方法的第一條語句(不考慮註釋語句)。

(2)只能在一個構造方法中使用this語句來呼叫類的其他構造方法,而不能在例項方法中用this語句來呼叫類的其他構造方法。

(3)只能用this語句來呼叫其他構造方法,而不能通過方法名來直接呼叫構造方法。

以上是本人對這個問題的一些理解。若有不正確,請各位dalao斧正。感謝~