Java 重载和覆盖的方法

Java Overloaded AND Overridden Methods

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

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

既然这段代码中同时存在重载和覆盖,那是否意味着它在编译时进行了静态绑定(针对class A中的匹配方法),然后在运行时进行了动态绑定(到 class B 中的方法)。它们可以同时出现吗?

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

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
        
    }
}

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

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

Since overloading and overriding both exist in this code, does that mean that it performed static binding at compile time (to the matching method in class A) and then dynamic binding at run time (to method in class B)

没错。编译器根据变量的类型选择匹配的签名,这是静态的(在本例中为A)。

在运行时,Java 找到编译器选择的签名的实现。这是动态的,基于 obj3 的运行时 class(在本例中为 B)。

再一次尝试说清楚:

超载

重载意味着单个 class 具有多个具有 不同参数类型 (又名签名)的方法,而您恰好为它们指定了相同的名称。如果您将方法更改为单独的名称,例如,您的程序将以相同的方式工作。 methodI(Integer n)methodS(String s)methodSI(String s, Integer n)

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

编译器根据 compile-time 类型 参数表达式.

解决重载问题]

例如如果你写

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

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

覆盖

覆盖是指在运行时JVM根据运行时class“点前对象”[=]调用方法实现。 50=].

并且在这种情况下,“方法”将被读取为编译器找到的与参数列表匹配的重载方法版本。所以,runtime 已经知道是 methodI()methodS() 还是 methodSI() 的意思,只决定从哪个 class 执行。

个人意见

允许多个方法共享相同的名称,但参数列表不同(又名重载),这会产生太多的混乱。