我试图理解Java. 有一些代码:
class A {
A getThis() {
System.out.println("call getThis() from A");
return this; //(3)
} //(3)
Object getSuper() {
System.out.println("call getSuper() from A");
return null;}
}
class B extends A {
B getThis() {
System.out.println("call getThis() from B");
return this;
}
A getSuper() {
System.out.println("call getSuper() from B");
return super.getThis();
}
}
class Tester {
public static void main (String[] args) {
Object a = new B().getSuper(); //(1)
System.out.println(a);
a = new B().getSuper().getSuper(); //(2)
System.out.println(a);
}
}
结果,控制台上显示以下文本:
从 B 调用 getSuper()
从 A 调用 getThis()
B@25154f
从 B 调用 getSuper()
从 A 调用 getThis()
从 B 调用 getSuper()
从 A 调用 getThis()
B@10dea4e
我预计当第 (1) 行被处理时,a类的一个实例将在 中A,而在第 (2) 行被处理后,a它将是null。为什么this从第 (3) 行返回的结果不是返回父类的引用,而是返回原始类的引用?
据我了解,当创建一个类的实例时B,它会存储对父类实例的引用A。我看到间接证实了我的话:
当调用类构造函数时B,类构造函数被调用A。即使在重写f类 B 中的方法时,您也可以通过;访问f类方法。
尽管如此,在处理类的实例时,我看不到一种方法可以从中返回对其中使用的类实例的引用。有什么办法可以使这成为可能吗?Asuper.f()BA
我认为您混淆了类和对象的概念。
类是一种描述实体的方式,它定义了依赖于该状态的状态和行为,以及与该实体(合约)交互的规则。
对象(实例)是类的独立代表,具有完全由类定义的特定状态和行为。
this关键字并不指向一个类,而是指向该类的一个实例(一个对象)。super 关键字提供对同一对象的属性和方法的访问,但在超类中进行了描述。
例如:你创建了一个类的对象
бирюса,Холодильник类Холодильник继承自类БытоваяТехника。对象бирюса既是冰箱又是家用电器。this 将返回对对象的引用бирюса,无论通过Холодильникor接收到哪个类的引用БытоваяТехника,对象都不会因此发生变化。所以你的对象
a是类的一个实例,B同时它是类的一个实例А,因为它是从它继承的。当你在链中调用 getSuper() 方法时,this 作为结果返回,即对象的引用a类和对象定义取自此处。
这个答案是针对这里涌入的“对超类的引用”的问题。它的措辞略有不同。
不,它没有被存储。类的实例是类
B的实例。为了更清楚,考虑一下继承机制是如何在 Java、C++ 和许多其他语言中实现的。A让类
A定义如下:然后此类的实例在内存中将具有以下形式:
其中
ref是对包含类实例数据的内存区域的引用。在上图中,可以看出两个特点:
在继承的情况下:
属于父类的数据附加到属于子类的数据:
这一大堆并指定了该类的一个实例
B。您可以看到对它的引用与对类实例的引用完全相同A。因此,将链接提升到层次结构只是简单地重命名现有链接。“对父类实例的引用”用在真正引用的嵌套类中,但不只是引用父类,而是引用关闭类。
向上转换总是隐式地(自动地)完成:
所有这些魔法的发生都是因为虚拟机知道所有类的整个层次结构,因此它可以显式或隐式地替换对层次结构中向上的方法的调用。
为了理解为什么调用本类的方法时无法获取到基类实例的引用,在继承者中,需要了解调用继承方法在java中是如何工作的。
首先,我们在内存中创建一个对象,其中包含从父对象继承的所有字段。并且这个对象可以通过一个链接访问,并且它不包含任何嵌套的父对象。
this在调用构造函数A和时比较引用B。其次,实例方法与对象的字段分开存储,
A甚至B通过类在对象上调用从类继承的方法А。但是当调用继承的方法时,它们会传递一个对调用它们的子实例的引用。因此,可以说,该方法是在所创建对象的实际实例上调用的。在创建继承类B时类A的构造函数的调用是在JVM的工作级别执行的,并且只是为了初始化类B的对象的字段,无法通过编程方式获取此引用,因为 A 类不存在。但是如果 B 类是 A 类的内部类,那么它将存储对 A 类对象的引用。