Java中的继承和重载

Ask*_*ker 6 java methods inheritance invoke

我正在攻读考试,我需要一些帮助才能理解以下剪辑代码中发生了什么.

class A {
    public void method1(A X) {
        System.out.println("A");
    }
}
class B extends A {
    public void method2() {
        System.out.println("B");
    }
}
class C extends B {
    public void method1(A x) {
        System.out.println("C");
    }
}
class D extends C {
    public void method1(D x) {
        System.out.println("D");
    }
}
public class test {
    public static void main(String[] args) {
        C c = new D();
        B b = c;
        c.method1(c);  // prints C
        b.method1(b);  // prints C
    }
}
Run Code Online (Sandbox Code Playgroud)

好吧,这就是我的想法:c.method1(c)在C中调用method1而在D中调用method1,因为c作为C是decleard,因此D中的method1不可见.但是b.method1(b)更难.B没有method1,我假设将使用超类中的method1,但事实并非如此.为什么在C中使用该方法?我在B中添加了一个新的D但是D的特化没有任何可见,因为b来自B型.

mpr*_*vat 5

总之,这是每个继承级别的每个方法的可见性:

D级:

public void method1(D x) { System.out.println("D"); }
public void method1(A x) { System.out.println("C"); }
public void method2()    { System.out.println("B"); }
Run Code Online (Sandbox Code Playgroud)

C级:

public void method1(A x) { System.out.println("C"); }
public void method2()    { System.out.println("B"); }
Run Code Online (Sandbox Code Playgroud)

B级:

public void method1(A x) { System.out.println("A"); }
public void method2()    { System.out.println("B"); }
Run Code Online (Sandbox Code Playgroud)

A类:

public void method1(A x) { System.out.println("A"); }
Run Code Online (Sandbox Code Playgroud)

同样重要的是要指出示例中的变量'c'和'b'是同一个对象,并且是一个实例 D.

所以...如果你打电话c.method1(c);,它打印"C",因为D是A的实例(它实际上是D,但它也是A的继承),所以你可以调用method1(A),对于D,打印"C".(那是满嘴).为什么不打印"D"你会问?因为变量声明为a C,编译器只能链接到该变量method1(A).

如果你打电话b.method1(b);,它打印"C",因为你的变量b实际上是a的一个实例D,因为你创建它new D().实际上cb指向同一类型的对象D.

调用方法时,JVM会查看D此例中对象的实际类型,而不是它所声明的内容B.

记住的一个好方法是当你有类似的东西时

B b = new D()

等式的左边部分主要由编译器使用.请记住,method1(A)并且method1(D)是两种不同的方法(因为不是完全相同的签名,不同的参数类型).

等式的右边部分由JVM在运行时使用.它定义了该变量在运行时的实际类型b.


Som*_*Guy 1

让我们以示例代码为例并注释调用哪个方法、为什么调用它以及为什么这里不是所有内容都继承。

\n\n
class A {\n    public void method1(A X) {\n        System.out.println("A");      <--|\n    }                                    |\n}                                        |\nclass B extends A {                      |\n    public void method2() {              | This is the only overriding happening\n        System.out.println("B");         | because they share the signature method1(A)\n    }                                    | The other signatures are method1() from class B\n}                                        | and method1(D) from class D\nclass C extends B {                      |\n    public void method1(A x) {           |\n        System.out.println("C");         |\n    }                             -------\n}\nclass D extends C {\n    public void method1(D x) {\n        System.out.println("D");\n    }\n}\npublic class test {\n    public static void main(String[] args) {\n        C c = new D();\n        B b = c;\n        c.method1(c);  // prints C\n        b.method1(b);  // prints C\n    }\n}   \n
Run Code Online (Sandbox Code Playgroud)\n\n

由于您正在从定义的对象调用 method1,因为C您正在获取结果 C。 \n尽管该类有方法,但该类已知的唯一方法 \xc2\xb4Object是 method1(A) 和 method1()。由于您的类被定义为 C,它将正确调用类中的方法C,因为类中的 method1 函数D不会覆盖类中的方法C

\n\n

编辑以回答您的评论:

\n\n

method1(A)此时您正在调用带有签名的方法。由于您Object实际代表\xc2\xb4s 该类,D它会注意到该方法method1(A)被先前继承的类覆盖C,因此将打印C。用基本的话来说,类的定义定义了允许您调用哪些方法(在对象的可见范围内),但它所引用的对象的实际类型定义了如何调用该方法(如果它\xc2\ xb4s 在某些时候会被覆盖)。

\n