Java:从子类

时间:2018-09-06 18:11:38

标签: java inheritance

我知道这个问题已经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;
        }
    }
}

2 个答案:

答案 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相等,并且xy相等。 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()