3

在下面的程序中,我在类 A 中的一个方法重载了 3 次,然后在子类 B 中,所有 3 个重载方法都被覆盖。

obj3 是一个具有引用类型 A(超类)和对象类型 B(子类)的对象,它在执行时从 B 调用方法,这是预期的行为。

由于此代码中都存在重载和覆盖,这是否意味着它在编译时执行静态绑定(到 A 类中的匹配方法),然后在运行时执行动态绑定(到 B 类中的方法)。它们可以同时发生吗?

我的假设是,这是动态绑定的经典案例,因为我认为“绑定”是一种永久性操作,但同行建议它是一起的(首先是静态的,然后是动态的)。

class A{
    
    public void method(Integer n){
        System.out.println("Integer: "+n);
    }
    
    public void method(String s){
        System.out.println("String: "+s);
    }
    
    public void method(String s, Integer n){
        System.out.println("String: "+s+" Integer: "+n);
    }
}

class B extends A{
    
    public void method(Integer n){
        System.out.println("Integer(from B): "+n);
    }
    
    public void method(String s){
        System.out.println("String(from B): "+s);
    }
    
    public void method(String s, Integer n){
        System.out.println("String(from B): "+s+" Integer(from B): "+n);
    }
}

public class Test{
    public static void main(String[] args){
        A obj1 = new A();
        B obj2 = new B();
        A obj3 = new B();
        
        System.out.println("Integer form of method");
        // Integer form of method

        System.out.println("Ref A Obj A");
        // Ref A Obj A
        obj1.method(1);
        // Integer: 1
        
        System.out.println("Ref B Obj B");
        // Ref B Obj B
        obj2.method(2);
        // Integer(from B): 2
        
        System.out.println("Ref A Obj B");
        // Ref A Obj B
        obj3.method(3);
        // Integer(from B): 3
        
    }
}
4

3 回答 3

4

你说得对。编译器在类中的重载之间进行静态选择A,并将该信息.class以方法 FQN 的形式放入文件中。

然后运行时在该方法的实现之间动态选择。

于 2020-09-02T07:22:58.403 回答
4

由于此代码中都存在重载和覆盖,这是否意味着它在编译时执行静态绑定(到 A 类中的匹配方法),然后在运行时执行动态绑定(到 B 类中的方法)

对。编译器选择匹配的签名,这是静态的,基于变量的类型(A在这种情况下)。

在运行时,Java 找到编译器选择的签名的实现。这是动态的,基于obj3( B,在这种情况下) 的运行时类。

于 2020-09-02T07:23:15.573 回答
0

再一次尝试说清楚:

重载

重载意味着单个类有多个具有不同参数类型(又名签名)的方法,而您只是碰巧给它们取了相同的名称。如果您将方法更改为单独的名称,例如methodI(Integer n)methodS(String s)和,您的程序将同样工作methodSI(String s, Integer n)

或者,您可以想象编译器在内部总是将这样的类型列表附加到方法名称。

编译器根据参数表达式的编译时类型来解决重载问题。

例如,如果你写

Object par = "Test";
a.method(par);

你得到一个编译器错误。即使我们都看到它是String你传递给方法的,编译器只看到一个Object,并且找不到匹配的方法。仅当您要引入额外method(Object o)的 时,编译器才会选择那个。运行时会调用该方法而不是字符串版本

覆盖

覆盖意味着在运行时JVM根据“点前对象”运行时类调用方法实现。

在这种情况下,“方法”将被读取为编译器找到的与参数列表匹配的重载方法版本。因此,运行时已经知道methodI(), methodS(), ormethodSI()是什么意思,并且只决定从哪个类中获取实现。

个人意见

允许多个方法共享相同的名称,但参数列表不同(也称为重载),这会产生过多的混淆,从而带来好处。

于 2020-09-02T09:06:12.497 回答