首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Java静态和动态绑定、重载

Java静态和动态绑定、重载
EN

Stack Overflow用户
提问于 2016-01-18 23:47:18
回答 4查看 866关注 0票数 2

我正在练习一个测试,我遇到了这个关于重载、静态和动态绑定的练习。将询问以下代码的输出:

代码语言:javascript
复制
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的打印方法。因为我们传递一个Moe类型的对象来打印,相应的带有参数类型Moe的打印方法在Curly中运行。这个方法的输出是Curly 1,正确的答案。

然而,当我将这一技术应用于以下几行时,我最终得到了错误的答案。有人能解释一下这个概念在Java中到底是如何工作的吗?

代码的正确输出是:

代码语言:javascript
复制
Curly 1
Curly 2
Curly 2
Larry 1
Curly 1
Curly 1
Larry 2
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2016-01-19 00:13:53

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

  • 静态绑定负责选择应该执行的方法的签名(名称和参数类型)。它用
代码语言:javascript
复制
- _name_ of method 
- type of variables holding arguments (compiler doesn't assume what actual object variable will hold at runtime, he picks signature which will be able to handle all of possible cases).

编译器从调用的方法的变量类型中选择签名,因此Object o = "abc";将不允许您调用o.substring(1,2);,因为编译器将无法在Object类中找到substring(int, int)签名(这是调用substring方法的o变量的类型)。

  • 动态绑定负责在编译时查找和调用静态绑定所选择的方法的代码。它将尝试在变量保存的实际实例类型中找到方法代码。换句话说,如果您有Animal a = new Cat(); a.makeSound();,您可以期望得到结果"Mew",因为在运行时,JVM将从Cat类开始搜索和调用makeSound代码。如果在该类中不提供实现,JVM将在祖先中搜索它,直到它找到继承它的祖先。

我在示例中重命名了类和变量,希望能使其更易读:

代码语言:javascript
复制
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)。

所以,当我们执行

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

同样地,在bc.print(new C());的情况下

  • 静态绑定将试图为print类中可用的C参数找到最佳的B方法,对于C来说,该方法是print(B) (因为没有print(C),而B是最近的超级类型)。
  • 因此,现在动态绑定知道在C类中查找哪个方法(因为这是bc持有的实例)。

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

票数 5
EN

Stack Overflow用户

发布于 2016-01-18 23:59:02

下面是正在发生的事情:

代码语言:javascript
复制
stooge1.print(new Moe()); // All three have overload for Moe,
// so the overload from the dynamic type of stooge1 gets called
stooge1.print(new Curly()); // Compiler thinks stooge1 is Larry,
// so it does not know that it has an overload for Curly.
// It uses the overload for Larry instead, because Curly is a Larry
stooge1.print(new Larry()); // Same logic as above applies.
stooge2.print(new Curly()); // Compiler thinks stooge2 is Moe, so its only overload
// is for Moe. Since the dynamic type is Larry, first overload is invoked

其余三个案例可以通过应用上述相同的逻辑来解决。

票数 1
EN

Stack Overflow用户

发布于 2016-01-18 23:59:28

对于#1,#2,#3,stooge1被声明为Larry,因此只能调用Larry可用的方法。

传递一个Moe将调用print(Moe)。因为实际的类是Curly,所以它会打印"Curly 1“。

传递一个Larry将调用print(Larry),因为这是与print(Moe)更好的匹配。这将打印“卷2”。

传递一个Curly也会调用print(Larry)。注意,print(Curly)stooge1来说是未知的,所以编译器不能选择它。因此,它也打印“卷2”。

现在试着找出剩下的。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34866199

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档