我知道这个问题已经here被问到,但是我无法理解“为什么”部分。
让我们以以下示例为例:
public class First {
First() {
System.out.println(super.getClass());
}
}
public class Second extends First {
Second() {
System.out.println(super.getClass());
}
}
public class Third extends Second {
Third() {
System.out.println(super.getClass());
}
}
当我实例化类型为Third的对象时:
public class Main {
public static void main(String[] args) {
Third third = new Third();
}
}
输出为:
class Third
class Third
class Third
我所期望的是(认为super.getClass()应该返回父类的名称):
class java.lang.Object
class First
class Second
哪个表明我不理解继承在Java中的实际工作方式。请帮助我弄清楚正确的概念。
编辑
我的实际目的是了解继承的实际工作原理(Jeff对此进行了很好的解释),而不是获得预期的输出。
当我试图了解以下代码为何起作用时(更具体地讲,当super.equals(point3d)传递给Point3D类型的对象时,为什么它起作用了),就引起了这个疑问。
public class Main {
public static void main(String[] args) {
Point3D p1 = new Point3D(1, 2, 3);
Point3D p2 = new Point3D(1, 2, 3);
System.out.println(p1.equals(p2)); // Output: true
}
}
public class Point {
private int x;
private int y;
public Point() {
this.x = 0;
this.y = 0;
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object object) {
if (object != null && object.getClass() == this.getClass()) {
Point point = (Point) object;
return point.x == this.x && point.y == this.y;
} else {
return false;
}
}
}
public class Point3D extends Point {
private int z;
public Point3D() {
this.z = 0;
}
public Point3D(int x, int y, int z) {
super(x, y);
this.z = z;
}
@Override
public boolean equals(Object object) {
if (object != null && object.getClass() == this.getClass()) {
Point3D point3D = (Point3D) object;
return super.equals(point3D) && point3D.z == this.z; // Had doubt here
} else {
return false;
}
}
}
答案 0 :(得分:4)
重要的是要认识到这里恰好有一个带有一个参考的对象。好像超类是在您的Third实例中驻留的Second的单独实例一样,很可能会提出它,但这不是真的。无法引用该实例,因为它不存在。
要明确:并非并非如此,在Third中没有super
所指的Second的隐藏实例,而在Second中有First,而在First中没有Object。 相反,只有一个对象能够充当对象,第一,第二或第三对象。不管本地变量或引用的类型(“静态类型”)如何,实例本身都具有“运行时类型”,即“第三”。
super
唯一可以为您做的事就是deliberately invoke a member that belongs to a superclass (JLS 15.11.2),该事件可能会被覆盖或命名隐藏。这里没有任何作用,因为getClass()
是在对象上声明的final
方法。 getClass
的文档中包含“返回此对象的运行时类”(docs)。不可能有不同的实现方式,因此您总是会像在问题中一样收到“第三”类型。
更新:与getClass
不同,equals
不是{final
,可以被覆盖。 Point.equals
确保getClass
返回的Class相等,并且x
和y
相等。 Point3D不会编写equals
的完全不同的实现,而是遵照Point的equals
的定义,并另外检查z
字段是否相等,因为Point检查{{1} },而不是object.getClass() == this.getClass()
。它不能仅通过调用object.getClass() == Point.class
来完成此操作,因为这将使用equals
实现;相反,它必须调用Point3D.equals
来查看Point如何计算super.equals
。
但是,我希望这是一个课程的示例,因为多态性断言Point3D是-Point,并且可以执行Point可以执行的任何操作(请参见Liskov Substitution Principle)。对于Point和Point3D,这可能会引起误解:您可以编写一种方法equals
,该方法可以使用2D点按预期工作,但使用3D点时却给出错误的结果。在实际环境中,您需要注意类层次结构及其所隐含的含义。
答案 1 :(得分:3)
getClass()
是Object
上的一种方法。每个子类都没有单独的子类。如果您想像这样往上走,请在getSuperclass()
的结果上致电getClass()
。