且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

关于Java重载的问题&动态绑定

更新时间:2023-10-16 23:21:40

由于您已经了解案例1,3和4,让我们解决案例2.

Since you already understand case 1, 3, and 4, let's tackle case 2.

(请注意 - 我绝不是JVM或编译器内部工作的专家,但这是我理解它的方式。如果有人读这篇文章是JVM专家,请随时编辑这个答案您可能会发现任何差异。)

(Please note - I am by no means an expert on the inner workings of the JVM or compilers, but this is how I understand it. If someone reading this is a JVM expert, feel free to edit this answer of any discrepancies you may find.)

子类中具有相同名称但签名不同的方法称为方法重载。方法重载使用静态绑定,这基本上意味着在编译时将强制选择(即绑定)适当的方法。编译器不知道对象的运行时类型(也就是实际类型)。所以当你写:

A method in a subclass that has the same name but a different signature is known as method overloading. Method overloading uses static binding, which basically means that the appropriate method will be forced to be "chosen" (i.e. bound) at compile-time. The compiler has no clue about the runtime type (aka the actual type) of your objects. So when you write:

                         // Reference Type  // Actual Type
    Sub sub = new Sub(); // Sub                Sub
    Top top = sub;       // Top                Sub

编译器只知道top是Top类型(也就是引用类型) )。所以当你后来写:

the compiler only "knows" that top is of type Top (aka the reference type). So when you later write:

    System.out.println(top.f(str)); // Prints "subobj"

编译器看到调用'top.f'指的是***的f方法。它知道str是String类型,它扩展了Object。因此,1)调用'top.f'引用Top类的f方法,2)类Top中没有f方法接受String参数,3)因为str是Object的子类,Top类的f方法是编译时唯一有效的选择。因此编译器隐式地将str向上转换为其父类型Object,因此可以将其传递给Top的f方法。 (这与动态绑定形成对比,其中上述代码行的类型解析将推迟到运行时,由JVM而不是编译器解析。)

the compiler "sees" the call 'top.f' as referring to the Top class's f method. It "knows" that str is of type String which extends Object. So since 1) the call 'top.f' refers to Top class's f method, 2) there is no f method in class Top that takes a String parameter, and 3) since str is a subclass of Object, the Top class's f method is the only valid choice at compile time. So the compiler implicitly upcasts str to its parent type, Object, so it can be passed to Top's f method. (This is in contrast to dynamic binding, where type resolution of the above line of code would be deferred until runtime, to be resolved by the JVM rather than the compiler.)

然后在运行时,在上面的代码行中,top被JVM向下转换为它的实际类型sub。但是,参数str已被编译器向上转换为Object类型。所以现在JVM必须在类sub中调用f方法,该方法接受Object类型的参数。

Then at runtime, in the above line of code, top is downcast by the JVM to it's actual type, sub. However, the argument str has been upcast by the compiler to type Object. So now the JVM has to call an f method in class sub that takes a parameter of type Object.

因此,上面的代码行打印subobj而不是 sub。

Hence, the above line of code prints "subobj" rather than "sub".

另一个非常相似的例子,请参阅: Java动态绑定和方法重写

For another very similar example, please see: Java dynamic binding and method overriding

更新:发现这篇关于JVM内部工作原理的详细文章:

Update: Found this detailed article on the inner workings of the JVM:

http://www.artima。 com / underthehood / invocationP.html

我评论了你的代码,以便更清楚地了解发生了什么:

I commented your code to make it more clear what's going on:

class Top {
    public String f(Object o) {return "Top";}
}

class Sub extends Top {
    public String f(String s) {return "Sub";} // Overloading = No dynamic binding
    public String f(Object o) {return "SubObj";} // Overriding = Dynamic binding
}

public class Test {
    public static void main(String[] args) {  

                                  // Reference Type     Actual Type
        Sub sub = new Sub();      // Sub                Sub
        Top top = sub;            // Top                Sub
        String str = "Something"; // String             String
        Object obj = str;         // Object             String

                                        // At Compile-Time:      At Run-Time:
        // Dynamic Binding
        System.out.println(top.f(obj)); // Top.f (Object)   -->  Sub.f (Object)

        // Dynamic Binding
        System.out.println(top.f(str)); // Top.f (Object)   -->  Sub.f (Object)

        // Static Binding
        System.out.println(sub.f(obj)); // Sub.f (Object)        Sub.f (Object)

        // Static Binding
        System.out.println(sub.f(str)); // Sub.f (String)        Sub.f (String)
    }
}