[英]How is the 'this' variable in Java actually set to the current object?
考慮:
class TestParent{
public int i = 100;
public void printName(){
System.err.println(this); //{TestChild@428} according to the Debugger.
System.err.println(this.i); //this.i is 100.
}
}
class TestChild extends TestParent{
public int i = 200;
}
public class ThisTest {
public static void main(String[] args) {
new TestChild().printName();
}
}
我知道有類似的問題已被提出,但我無法對Java中的'this'變量有一個明確的理解。
讓我試着解釋一下我是如何理解上面圖像的結果的。
由於它是一個調用printName()
方法的new TestChild()
對象,因此第6行中的this
變量根據調試器設置為TestChild
對象 - {TestChild @ 428}。
然而,由於Java沒有一個虛擬場-我不能完全肯定這是什么意思,但我在概念上把它理解為是Java方法,它支持多態相反- this.i
設置為100 TestParent
在編譯時間。
所以不管this
是什么, this.i
方法中的TestParent
將始終是TestParent
類中的i
變量。
我不確定我的理解是否正確所以如果我錯了請糾正我。
而且,我的主要問題是,
如何this
變量設置為調用方法的當前對象? 它是如何實際實現的?
從本質上講,兩者之間沒有區別
this.foo()
和
anyObject.foo()
因為兩者都以同樣的方式“實施”。 請記住,“最終”“面向對象只是一種抽象 ,在”現實“中發生的事情是這樣的:
foo(callingObject)
換句話說:無論何時使用某個對象引用來調用方法......最后都沒有對某個對象進行調用。 因為在匯編程序和機器代碼的深處,不存在諸如“對某事物的調用”之類的東西。
真正發生的是對函數的調用; 第一個(源代碼級別隱式/不可見)參數是該對象。
順便說一句:你實際上可以用Java寫下來:
class Bar {
void foo(Bar this) { ... }
以后用
new Bar().foo();
對於this.fieldA,最后:你有一個對內存中某個位置的引用; 和一個表,告訴你哪個“偏移”你會找到fieldA。
編輯 - 僅供記錄。 如果你對foo(Bar this)的更多細節感興趣 - 你可以轉向這個問題 ; 在Java規范中提供詳細信息!
這里發生的是有兩個完全不同的領域,都稱為i
; 使用他們的全名,一個是TestParent::i
,一個是TestChild::i
。
因為printName
方法是在TestParent
定義的, TestParent
當它引用i
,它只能看到TestParent::i
,它被設置為100。
而當你在TestChild
中將i
設置為200時,兩個名為i
字段都是可見的,但由於它們具有相同的名稱, TestChild::i
隱藏了 TestParent::i
,最后設置了TestChild::i
並離開TestParent::i
不變。
好吧,當創建一個新對象時,該對象在內存中有一個地址,因此您可以將其視為該對象具有私有成員, this
成員在創建對象時設置為該地址。 你也可以這樣想: obj.method(param)
只是method(obj, param);
語法糖method(obj, param);
this
實際上是method
的參數。
直接解決你在輸出中看到的內容:對'this.i'的調用是作為參數傳遞給'print()'當前范圍中字段'i'的值,這是父類的范圍。 相比之下,打印'this'的調用正在被翻譯成一個調用打印'this.getClass()。getName()'[粗略說],並且'getClass()'調用獲取實際的類對象,這是為兒童班。
在@Tom Anderson回答之上添加更多信息,這很好地解釋了隱藏概念。
我在Child( TestChild
)中添加了一個構造函數,它在父TestChild
和子TestChild
中都打印了i的值。
如果要從child( TestChild
)獲取i
值,請覆蓋TestChild
的方法。
class TestParent{
public int i = 100;
public void printName(){
System.err.println("TestParent:printName()");
System.err.println(this); //{TestChild@SOME_NUM} according to the Debugger.
System.err.println(this.i); //this.i is 100.
}
}
class TestChild extends TestParent{
public int i = 200;
public TestChild(){
System.out.println("TestChild.i and TestParent.i:"+this.i+":"+super.i);
}
public void printName(){
//super.printName();
System.err.println("TestChild:printName()");
System.err.println(this); //{TestChild@SOME_NUM} according to the Debugger.
System.err.println(this.i); //this.i is 200.
}
}
public class ThisTest {
public static void main(String[] args) {
TestParent parent = new TestChild();
parent.printName();
}
}
案例1:如果我評論super.printName()
從小孩的呼叫,的子版本TestChild.printName()
打印i的值TestChild
輸出:
TestChild.i and TestParent.i:200:100
TestChild:printName()
TestChild@43cda81e
200
情況2:TestChild.printName()調用super.printName()作為printName()方法的第一行。 在這種情況下,來自父和子的i值都顯示在各自的方法中。
輸出:
TestChild.i and TestParent.i:200:100
TestParent:printName()
TestChild@43cda81e
100
TestChild:printName()
TestChild@43cda81e
200
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.