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'变量。
让我试着解释一下我是如何理解上图的结果的。
因为调用 printName()
方法的是 new TestChild()
对象,所以第 6 行中的 this
变量设置为 TestChild
对象 - {TestChild@428} 根据调试器。
但是,由于 Java 没有虚拟字段 - 我不完全确定这是什么意思,但我在概念上将其理解为 [=52= 的对立面] 方法,支持多态性 - this.i
在编译时设置为 TestParent
的 100。
所以无论 this
是什么,TestParent
方法中的 this.i
始终是 [=18= 方法中的 i
变量] class.
我不确定我的理解是否正确,如有错误请指正。
另外,我的主要问题是,
如何将 this
变量设置为调用该方法的当前对象?它是如何实际实施的?
本质上和
没有区别
this.foo()
和
anyObject.foo()
因为两者都是"implemented"相同的方式。请记住 "in the end" "object orientation is only an abstraction, and in " 现实”发生的事情是这样的:
foo(callingObject)
换句话说:无论何时您使用某个对象引用来调用方法...最终都不会调用 某个对象。因为在汇编程序和机器代码的深处, "a call on something" 之类的东西并不存在。
真正发生的是对函数的调用;第一个(源代码级别的implicit/invisible)参数是那个对象。
顺便说一句:您实际上可以将其写在 Java 中,例如:
class Bar {
void foo(Bar this) { ... }
以后使用
new Bar().foo();
而对于 this.fieldA,最后:您引用了内存中的某个位置;和一个 table 告诉你在哪个 "offset" 上你会找到 fieldA。
编辑 - 仅作记录。如果你对 foo(Bar this) 的更多细节感兴趣 - 你可以转向这个 ;在其背后的 Java 规范中提供详细信息!
好吧,当创建一个新对象时,该对象在内存中有一个地址,因此您可以认为该对象有一个私有成员 this
,该成员设置为创建对象时的地址。你也可以这样想:obj.method(param)
只是method(obj, param);
的语法糖,this
其实是method
的一个参数。
这里发生的事情是有两个完全不同的字段都叫 i
;要使用他们的全名,一个是 TestParent::i
,一个是 TestChild::i
.
因为方法printName
定义在TestParent
中,当它引用i
时,只能看到TestParent::i
,设置为100。
而当您在 TestChild
中将 i
设置为 200 时,名为 i
的两个字段都可见,但由于它们具有相同的名称,TestChild::i
hides TestParent::i
,你最终设置 TestChild::i
并保持 TestParent::i
不变。
要直接解决您在输出中看到的内容:对 print 'this.i' 的调用将作为参数传递给 'print()' 当前范围中字段 'i' 的值,这是parentclass的范围。相比之下,对 print 'this' 的调用在后台被转换为对 print 'this.getClass().getName()' [粗略地说] 的调用,而 'getClass()' 调用得到实际的 class object,这是 child class.
在@Tom Anderson 回答的基础上添加更多信息,这很好地解释了隐藏概念。
我在 Child ( TestChild
) 中添加了一个构造函数,它在 parent 和 child 中打印 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:如果我评论来自 child 的 super.printName()
调用,TestChild.printName()
的 Child 版本打印 TestChild
[=20 中 i 的值=]
输出:
TestChild.i and TestParent.i:200:100
TestChild:printName()
TestChild@43cda81e
200
情况 2:TestChild.printName() 调用 super.printName() 作为 printName() 方法的第一行。在这种情况下,parent 和 child 中的 i 值都显示在各自的方法中。
输出:
TestChild.i and TestParent.i:200:100
TestParent:printName()
TestChild@43cda81e
100
TestChild:printName()
TestChild@43cda81e
200
考虑:
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 没有虚拟字段 - 我不完全确定这是什么意思,但我在概念上将其理解为 [=52= 的对立面] 方法,支持多态性 -
this.i
在编译时设置为TestParent
的 100。所以无论
this
是什么,TestParent
方法中的this.i
始终是 [=18= 方法中的i
变量] class.
我不确定我的理解是否正确,如有错误请指正。
另外,我的主要问题是,
如何将 this
变量设置为调用该方法的当前对象?它是如何实际实施的?
本质上和
没有区别this.foo()
和
anyObject.foo()
因为两者都是"implemented"相同的方式。请记住 "in the end" "object orientation is only an abstraction, and in " 现实”发生的事情是这样的:
foo(callingObject)
换句话说:无论何时您使用某个对象引用来调用方法...最终都不会调用 某个对象。因为在汇编程序和机器代码的深处, "a call on something" 之类的东西并不存在。
真正发生的是对函数的调用;第一个(源代码级别的implicit/invisible)参数是那个对象。
顺便说一句:您实际上可以将其写在 Java 中,例如:
class Bar {
void foo(Bar this) { ... }
以后使用
new Bar().foo();
而对于 this.fieldA,最后:您引用了内存中的某个位置;和一个 table 告诉你在哪个 "offset" 上你会找到 fieldA。
编辑 - 仅作记录。如果你对 foo(Bar this) 的更多细节感兴趣 - 你可以转向这个
好吧,当创建一个新对象时,该对象在内存中有一个地址,因此您可以认为该对象有一个私有成员 this
,该成员设置为创建对象时的地址。你也可以这样想:obj.method(param)
只是method(obj, param);
的语法糖,this
其实是method
的一个参数。
这里发生的事情是有两个完全不同的字段都叫 i
;要使用他们的全名,一个是 TestParent::i
,一个是 TestChild::i
.
因为方法printName
定义在TestParent
中,当它引用i
时,只能看到TestParent::i
,设置为100。
而当您在 TestChild
中将 i
设置为 200 时,名为 i
的两个字段都可见,但由于它们具有相同的名称,TestChild::i
hides TestParent::i
,你最终设置 TestChild::i
并保持 TestParent::i
不变。
要直接解决您在输出中看到的内容:对 print 'this.i' 的调用将作为参数传递给 'print()' 当前范围中字段 'i' 的值,这是parentclass的范围。相比之下,对 print 'this' 的调用在后台被转换为对 print 'this.getClass().getName()' [粗略地说] 的调用,而 'getClass()' 调用得到实际的 class object,这是 child class.
在@Tom Anderson 回答的基础上添加更多信息,这很好地解释了隐藏概念。
我在 Child ( TestChild
) 中添加了一个构造函数,它在 parent 和 child 中打印 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:如果我评论来自 child 的 super.printName()
调用,TestChild.printName()
的 Child 版本打印 TestChild
[=20 中 i 的值=]
输出:
TestChild.i and TestParent.i:200:100
TestChild:printName()
TestChild@43cda81e
200
情况 2:TestChild.printName() 调用 super.printName() 作为 printName() 方法的第一行。在这种情况下,parent 和 child 中的 i 值都显示在各自的方法中。
输出:
TestChild.i and TestParent.i:200:100
TestParent:printName()
TestChild@43cda81e
100
TestChild:printName()
TestChild@43cda81e
200