我正在为测试做练习,并且遇到了有关重载以及静态和动态绑定的练习。询问以下代码的输出:

class Moe {
    public void print(Moe p) {
        System.out.println("Moe 1");
    }
}

class Larry extends Moe {
    public void print(Moe p) {
        System.out.println("Larry 1");
    }
    public void print(Larry l) {
        System.out.println("Larry 2");
    }
}

class Curly extends Larry {
    public void print(Moe p) {
        System.out.println("Curly 1");
    }
    public void print(Larry l) {
        System.out.println("Curly 2");
    }
    public void print(Curly b) {
        System.out.println("Curly 3");
    }
}

class Overloading {
    public static void main (String [] args) {
        Larry stooge1 = new Curly();
        Moe stooge2 = new Larry();
        Moe stooge3 = new Curly();
        Curly stooge4 = new Curly();
        Larry stooge5 = new Larry();

        stooge1.print(new Moe());
        stooge1.print(new Curly());
        stooge1.print(new Larry());
        stooge2.print(new Curly());
        stooge3.print(new Curly());
        stooge3.print(new Larry());
        stooge5.print(new Curly());
    }
}


我想我获得了第一个,但在其他方面我完全迷失了。这是我解决第一个问题的方法:

在运行时,stooge1的类型为Curly,因此我们调用Curly的print方法。由于我们传递了Moe类型的对象进行打印,因此在Moe中运行了参数类型为Curly的相应打印方法。此方法的输出是正确的答案Curly 1

但是,当我将这种技术应用于以下几行时,我得到的答案是错误的。有人可以解释一下这个概念在Java中的工作原理吗?

该代码的正确输出是:

Curly 1
Curly 2
Curly 2
Larry 1
Curly 1
Curly 1
Larry 2

最佳答案

静态绑定在编译时发生,动态绑定在运行时发生。


静态绑定负责选择应执行的方法的签名(名称和参数类型)。它用


方法名称
带有参数的变量的类型(编译器不假设运行时实际的对象变量将保留,他选择可以处理所有可能情况的签名)。


编译器从调用方法的变量类型中选择签名,因此Object o = "abc";不允许您调用o.substring(1,2);,因为编译器将无法在substring(int, int)类(其为Object类型)中找到o签名。调用substring方法的变量)。
动态绑定负责在编译时查找和调用通过静态绑定选择的方法的代码。它将尝试查找变量持有的实际实例类型的方法代码。换句话说,如果您具有Animal a = new Cat(); a.makeSound();,则可以期望得到"Mew"作为结果,因为在运行时JVM将从makeSound类开始搜索并调用Cat的代码。如果在该类中未提供实现,则JVM将在祖先中搜索它,直到找到从其继承的继承。




我在示例中对类和变量进行了重命名,以期使其更具可读性:

class A {
    public void print(A a) {
        System.out.println("A.print(A)");
    }
}

class B extends A {
    public void print(A a) {
        System.out.println("B.print(A)");
    }
    public void print(B b) {
        System.out.println("B.print(B)");
    }
}

class C extends B {
    public void print(A a) {
        System.out.println("C.print(A)");
    }
    public void print(B b) {
        System.out.println("C.print(B)");
    }
    public void print(C c) {
        System.out.println("C.print(C)");
    }
}

class OverloadingDemo {
    public static void main (String [] args) {
        A ab = new B();
        A ac = new C();
        B bb = new B();
        B bc = new C();

        bc.print(new A());
        bc.print(new C());
        bc.print(new B());
        ab.print(new C());
        ac.print(new C());
        ac.print(new B());
        bb.print(new C());
    }
}


(保存类型为X的实例的类型为Y的变量命名->变量名为xy)。

所以,当我们执行

bc.print(new A());



静态绑定将尝试在类print中找到最佳的B方法签名,该类可以处理A类型的实例。在这种情况下,它将为print(A)
之后,动态绑定将在类C中搜索此方法的代码(因为这是bc变量持有的实例类型),这意味着我们将看到C.print(A)


对于bc.print(new C());同样


静态绑定将尝试为print类中可用的C参数找到最佳的B方法,对于Cprint(B)(因为那里没有print(C)并且B是最接近的超类型)。
因此,现在动态绑定知道要在C类中查找哪种方法(因为这是bc拥有的实例)。


因此它将调用C.print(B)

关于java - Java静态和动态绑定(bind),重载,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/34866199/

10-13 08:06