簡體   English   中英

Java中的'this'變量實際上是如何設置為當前對象的?

[英]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'變量有一個明確的理解。

讓我試着解釋一下我是如何理解上面圖像的結果的。

  1. 由於它是一個調用printName()方法的new TestChild()對象,因此第6行中的this變量根據調試器設置為TestChild對象 - {TestChild @ 428}。

  2. 然而,由於Java沒有一個虛擬場-我不能完全肯定這是什么意思,但我在概念上把它理解為是Java方法,它支持多態相反- this.i設置為100 TestParent在編譯時間。

  3. 所以不管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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM