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斧正。感謝~