简体   繁体   English

Java动态绑定

[英]Java dynamic binding

I am practicing for an exam, and found a sample problem that gets me totally lost. 我正在为考试练习,发现了一个使我完全迷失的样本问题。 For the following code, find what the output is: 对于以下代码,找到输出是什么:

class Moe {
    public void print(Moe p) {
        System.out.println("Moe 1\n");
    }
}
class Larry extends Moe {
    public void print(Moe p) {
        System.out.println("Larry 1\n");
    }
    public void print(Larry l) {
        System.out.println("Larry 2\n");
    }
}
class Curly extends Larry {
    public void print(Moe p) {
        System.out.println("Curly 1\n");
    }
    public void print(Larry l) {
        System.out.println("Curly 2\n");
    }
    public void print(Curly b) {
        System.out.println("Curly 3\n");
    }
}
public class Overloading_Final_Exam {
    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()); 
        ((Curly)stooge1).print(new Larry()); 
        ((Larry)stooge2).print(new Moe()); 
        stooge2.print(new Curly()); 
        stooge3.print(new Curly()); 
        stooge3.print(new Moe()); 
        stooge3.print(new Larry()); 
        ((Curly)stooge3).print(new Larry()); 
        ((Curly)stooge3).print(new Curly()); 
        stooge4.print(new Curly()); 
        stooge4.print(new Moe()); 
        stooge4.print(new Larry()); 
        stooge5.print(new Curly()); 
        stooge5.print(new Larry()); 
        stooge5.print(new Moe()); 
    }
}

I had my ideas in mind, but then when I ran the java, I got something totally different: 我想到了我的想法,但是当我运行Java时,我得到了完全不同的东西:

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

The first few ones are OK, but then I really don't understand. 前几个可以,但是我真的不明白。 Anyone has a good explanation for this problem? 有人对此问题有很好的解释吗?

Thanks 谢谢

I would start by drawing a picture... 我将从画一幅画开始...

Moe - print(Moe)
 |
Larry - print(Moe), print(Larry)
 |
Curly - print(Moe), print(Larry), print(Curly)

Then I would keep track of the variables: 然后,我将跟踪变量:

  • Larry - stooge1 -> Curly 拉里-stooge1->卷曲
  • Moe - stooge2 -> Larry 萌-stooge2->拉里
  • Moe - stooge3 -> Curly 萌-stooge3->卷曲
  • Curly - stooge4 -> Curly 卷曲-stooge4->卷曲
  • Larry - stooge5 -> Larry 拉里-stooge5->拉里

  • stooge1.print(new Moe())

    • stooge1 -> Curly so calls Curly.print(Moe) stooge1-> Curly,因此称为Curly.print(Moe)
  • ((Curly)stooge1).print(new Larry());

    • stooge1 -> Curly so calls Curly.print(new Larry()) stooge1-> Curly,因此称为Curly.print(new Larry())
  • ((Larry)stooge2).print(new Moe());

    • stooge2 -> Larry so calls Larry.print(new Moe()); stooge2-> Larry叫Larry.print(new Moe());
  • stooge2.print(new Curly());
    Ok, this is where it gets a bit trickier (sorry I stopped one before here) 好的,这有点棘手(对不起,我之前在这里停过一个)

    • stooge2 is declared to be a Moe. stooge2被声明为Moe。 So when the compiler is looking at what to call it is going to call the print(Moe) method. 因此,当编译器正在查看要调用的内容时,它将调用print(Moe)方法。 Then at runtime it knows that stooge2 is a Larry so it calls the Larry.print(Moe) method. 然后在运行时,它知道stooge2是Larry,因此它调用Larry.print(Moe)方法。

etc... 等等...

Let me know if following that all the way through doesn't work out for you. 让我知道,如果这样做对您没有帮助。

(updated to clarify the next one) (更新以澄清下一个)

So the general rule is: 因此,一般规则是:

  • the compiler looks at the variable type to decide what method to call. 编译器查看变量类型,以确定要调用的方法。
  • the runtime looks at the actual class that the variable is point at to decide where to get the method from. 运行时将查看变量所指向的实际类,以决定从何处获取方法。

So when you have: 因此,当您拥有:

Moe stooge2 = new Larry();
stooge2.print(new Moe());

the compiler says: 编译器说:

  • can Larry be assigned to stooge2? 可以将Larry分配给stooge2吗? (yes as Larry is a subclass of Moe) (是的,因为Larry是Moe的子类)
  • does Moe have a print(Moe) method? Moe是否具有print(Moe)方法? (yes) (是)

the runtime says: 运行时说:

  • I am supposed to call the print(Moe) method on this here object... stooge2 我应该在此对象上调用print(Moe)方法... stooge2
  • stooge2 is point at a Larry. stooge2指向拉里。
  • I'll call the print(Moe) method in the Larry class. 我将在Larry类中调用print(Moe)方法。

Once you have worked all that out try getting rid of some of the methods and see how that changes things. 完成所有这些工作后,请尝试摆脱一些方法,然后看看它会如何改变。

Actually, this problem is not as simple as it seems, since Java is both static and dynamically bound. 实际上,这个问题并不像看起来那样简单,因为Java是静态的而且是动态绑定的。 You have to understand where each is applied before you will understand all the results you are getting from this exercise. 您必须先了解每种方法的应用范围,然后才能理解从本练习中获得的所有结果。

The General rule mentioned by TofuBeer is only correct in the dynamic binding case. TofuBeer提到的一般规则仅在动态绑定的情况下才是正确的。 In static binding, decisions are only made at compile time. 在静态绑定中,决策仅在编译时做出。

Your example mixes the dynamic binding (when methods are overridden) and static binding (when methods are overloaded). 您的示例混合了动态绑定(当方法被重写时)和静态绑定(当方法被重载时)。

Take a look at this question for more details. 请查看此问题以获取更多详细信息。

A hint is to disregard the value on the left when looking at objects. 提示是在查看对象时忽略左侧的值。 Instead, look at the value of the right during the declaration, this is the actual value of the object. 而是在声明期间查看right的值,这是对象的实际值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM