Java重载和重载方法

问题描述

在下面的程序中,我在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
        
    }
}

解决方法

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

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

,

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

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

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

,

再进行一次澄清:

超载

重载意味着单个类具有不同参数类型(又称签名)的多个方法,而您刚好给它们使用了相同的名称。如果您将方法更改为单独的名称,例如methodI(Integer n)methodS(String s)methodSI(String s,Integer n)

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

重载由编译器根据参数表达式编译时类型解决。

例如如果你写

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

您收到编译器错误。即使我们都看到您正在传递给方法的是String,编译器也只会看到Object,并且找不到匹配的方法。仅当您要引入一个附加的method(Object o)时,编译器才会选择那个。然后运行时将调用该方法,而不是String版本

覆盖

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

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

个人意见

允许多个方法共享相同的名称,但参数列表不同(又名重载),会产生太多混淆,以致于其好处。