我有以下课程:
package com.zee.main;
import com.zee.sub.Sub;
public class MainClass {
public static void main(String[] args) {
Sub sub = new Sub();
sub.add();
}
}
package com.zee.sup;
public class Super
{
private int a = 2;
private int b = 3;
public void add(){
System.out.println("Result: "+(a+b));
System.out.println("Class:" +this.getClass().getName());
}
}
package com.zee.sub;
import com.zee.sup.Super;
public class Sub extends Super {
}
输出
Result: 5
Class:com.zee.sub.Sub
Subclass
如何继承Superclass
的方法?我假设Superclass
中定义的方法成为Subclass
的一部分但是当我检查Sub的编译字节码时,我发现没有定义add
方法在超级班。
// Compiled from Sub.java (version 1.6 : 50.0, super bit)
public class com.zee.sub.Sub extends com.zee.sup.Super {
// Method descriptor #6 ()V
// Stack: 1, Locals: 1
public Sub();
0 aload_0 [this]
1 invokespecial com.zee.sup.Super() [8]
4 return
Line numbers:
[pc: 0, line: 5]
Local variable table:
[pc: 0, pc: 5] local: this index: 0 type: com.zee.sub.Sub
}
以下是我的问题:
由于Sub的已编译字节码中没有add
方法,因此必须在运行时调用add
Superclass
方法。
矛盾的第一点是this.getClass().getName()
,它返回此Object的运行时类,但它的打印Sub
作为运行时类。
如果运行时类是Sub,那么它如何在a
方法中访问超类的私有字段b
和add
?
有人可以解释一下。提前致谢
答案 0 :(得分:3)
你的“问题”不是问题,而是回应它们:
如果您反汇编main
方法,则会看到invokevirtual
对add()
的调用。这告诉JVM查找在类层次结构中调用的适当方法,从子类开始,如果没有在那里找到实现,就会向上运行。
Object#getClass()
是Java中的一种特殊基础结构方法。 It's implemented with native
code并挂钩到JVM内部,以识别相关对象的类。
班级Sub
不访问私人会员。 Super
中的代码可以访问它们。
答案 1 :(得分:3)
由于Sub的编译字节码中没有add方法,因此添加 必须在运行时调用Superclass的方法。
是的,根据定义,方法调用是一个运行时程序。
矛盾的第一点是this.getClass()。getName() 返回此Object的运行时类,但其打印Sub为 运行时类。
这里没有矛盾。 add()
方法在超类中定义,它没有在子类中重新定义,因此当在子类上调用add
时,将调用超类中的方法。
如果运行时类是Sub,那么它是如何访问私有的 超类的字段a和b在其add方法中?
它是通过超类中的一个方法来访问它们的,它可以访问该类的私有实例变量。正常范围规则适用。
这可能对你有所帮助:正如我所理解的,当一个类被放在一起时,我们可能会想到一个表中的方法列表。调用方法时,实际发生的是从“跳转表”中检索正确方法的地址。在这种情况下,add()
的跳转表中的位置被超类方法的地址占用。反过来,该方法具有访问私有变量等内容的偏移量;该类的设置巧妙地将它们放在子类和超类中的相同偏移处,这样它们就可以在两个地方工作。
因此,为子类调用的add
方法实际上是相同的方法,使用相同的实例变量位置,就像对超类一样。
我希望这有助于解释事情。
答案 2 :(得分:-2)
Sub可以从Superclass访问私有字段,因为Sub是Superclass类型,并且在调用Superclass中定义的方法时可以访问这些私有字段。但是,当您尝试创建仅属于Sub类的方法时,它不能调用这些字段,因为Superclass将对其子字段的“直接”访问权限“直接”访问。