Java JVM如何在内部区分方法重载和方法重写?

Java JVM如何在内部区分方法重载和方法重写?,java,Java,我想知道JVM在内部是如何区分方法重载和方法重写的。尽管方法重载和重写的名称保持不变,但主要区别在于方法重载是在编译时解决的,而方法重写是在运行时解决的。在Java中重写或重载方法的规则也不同。例如,private、static和final方法在Java中不能被重写,但您仍然可以重载它们。对于重写,方法的名称和签名必须保持相同,但对于重载,方法签名必须不同。最后但并非最不重要的区别是,在Java中,对重载方法的调用是使用静态绑定解决的,而对重写方法的调用是使用动态绑定解决的。因此JVM不涉及重载

我想知道JVM在内部是如何区分方法重载和方法重写的。

尽管方法重载和重写的名称保持不变,但主要区别在于方法重载是在编译时解决的,而方法重写是在运行时解决的。在Java中重写或重载方法的规则也不同。例如,private、static和final方法在Java中不能被重写,但您仍然可以重载它们。对于重写,方法的名称和签名必须保持相同,但对于重载,方法签名必须不同。最后但并非最不重要的区别是,在Java中,对重载方法的调用是使用静态绑定解决的,而对重写方法的调用是使用动态绑定解决的。因此JVM不涉及重载
方法重载:

方法重写:


中的Jvm不涉及方法重载。因此,它不必区分方法重载和方法重写

如果您了解Java是如何在幕后实现方法重载和方法重写的,您就会清楚地理解这一点。

在讨论重载和重写之间的区别之前,让我们先看看多态性

什么是多态性?

多态性是一种方法根据其作用的对象执行不同操作的能力。换句话说,多态性允许您定义一个接口并有多个实现

java中不同类型的多态性。 1) 方法重载 2) 方法重写

java中的多态类型:静态、动态、运行时和编译时

现在让我们回到原来的问题,理解重载和重写之间的区别

1。第一个也是最重要的是,方法重载编译时多态性,而方法重写是运行时多态性。所以JVM只需要处理方法重写。编译后已解决方法重载问题。

2.在方法重载中,方法必须具有不同的签名。在方法重写中,方法必须具有相同的签名。

还有很多不同之处,但以上两种方法确实可以区分方法重载和方法重写

在结束之前,让我们也看看每个人都在努力实现什么


方法重载是对方法的行为进行更多的“添加”或“扩展”。方法重写是“更改”方法的现有行为。

JVM只处理方法重写。通过在派生类中添加具有相同签名的方法来重写方法(唯一允许的差异是返回类型,它允许更具体)。签名对方法名称、参数类型和返回类型进行编码


方法重载意味着有多个具有相同“简单名称”但签名不同的方法。编译时,
javac
编译器根据参数的类型选择一个相同的命名方法,并将其签名放在编译后的
.class
文件中。编译后的Java字节码中的方法调用必须指定被调用方的签名。

方法重载由编译器处理(这就是为什么称为静态绑定),而重写由JVM处理

重载方法是不同的,并且可以根据参数列表单独识别,这就是为什么编译器在编译时解析重载方法

方法重写发生在我们试图对持有
子对象的
父对象
引用调用重写的方法时。因为我们在
parent
reference上调用方法,所以在编译时方法从
parent
reference类型得到解析,所以对于编译器,调用
parent
的方法。但是
parent
持有
child
的对象,因此在运行时从
child
调用方法

为了理解Java(编译器+JVM)如何在内部处理这两件事,让我们以哺乳动物和人类类为例

public class OverridingInternalExample {

    private static class Mammal {
        public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
    }

    private static class Human extends Mammal {

        @Override
        public void speak() { System.out.println("Hello"); }

        // Valid overload of speak
        public void speak(String language) {
            if (language.equals("Hindi")) System.out.println("Namaste");
            else System.out.println("Hello");
        }

        @Override
        public String toString() { return "Human Class"; }

    }

    //  Code below contains the output and bytecode of the method calls
    public static void main(String[] args) {
        Mammal anyMammal = new Mammal();
        anyMammal.speak();  // Output - ohlllalalalalalaoaoaoa
        // 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V

        Mammal humanMammal = new Human();
        humanMammal.speak(); // Output - Hello
        // 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V

        Human human = new Human();
        human.speak(); // Output - Hello
        // 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V

        human.speak("Hindi"); // Output - Namaste
        // 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
    }
}
当我们编译上述代码并尝试使用
javap-verbose OverridingInternalExample
查看字节码时,我们可以看到编译器生成一个常量表,在该表中为每个方法调用分配整数代码

我已经包括了字节码和上面的方法调用,通过查看上面的代码,我们可以看到
人类哺乳动物说话()
人类说话()
人类说话(“印地语”)的字节码
完全不同,因为编译器能够根据参数列表和类引用区分它们。这就是方法重载被称为静态多态性静态绑定的原因

但是
任何哺乳动物.speak()和
人类哺乳动物.speak()的字节码
是相同的,因为根据编译器,这两个方法都是在
哺乳动物
引用上调用的,但是两个方法调用的输出是不同的,因为在运行时JVM知道引用所持有的对象,JVM调用对象上的方法,这就是为什么方法重写被称为动态的原因多态性或简单的多态性


如果您想了解更多这方面的信息,可以阅读更多。

重载是编译时功能。JVM不参与其中。用@SotiriosDelimanolis一行简单而最好的答案!!
class Calculation{  
void sum(){System.out.println("sum in superclass");}  
}  
class Specific extends Calculation{  
void sum(){System.out.println("sum in Specific");}
}
public class OverridingInternalExample {

    private static class Mammal {
        public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
    }

    private static class Human extends Mammal {

        @Override
        public void speak() { System.out.println("Hello"); }

        // Valid overload of speak
        public void speak(String language) {
            if (language.equals("Hindi")) System.out.println("Namaste");
            else System.out.println("Hello");
        }

        @Override
        public String toString() { return "Human Class"; }

    }

    //  Code below contains the output and bytecode of the method calls
    public static void main(String[] args) {
        Mammal anyMammal = new Mammal();
        anyMammal.speak();  // Output - ohlllalalalalalaoaoaoa
        // 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V

        Mammal humanMammal = new Human();
        humanMammal.speak(); // Output - Hello
        // 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V

        Human human = new Human();
        human.speak(); // Output - Hello
        // 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V

        human.speak("Hindi"); // Output - Namaste
        // 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
    }
}