【问题标题】:Java Overloaded AND Overridden MethodsJava重载和重写方法
【发布时间】:2020-09-02 07:13:53
【问题描述】:

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

【问题讨论】:

  • 重载方法:编译时间(静态)。虚拟方法:运行时(动态)。
  • @paulsm4 是的,但是由于这个方法既是重载的又是虚拟的,有人告诉我,(静态和动态)绑定都会发生,在编译时是静态的,在运行时是动态的。他们的论点是“动态绑定”的含义是它改变了静态绑定方法的绑定。所以在上面的例子中,发生了从类 A 到方法(整数 n)的静态绑定,然后在运行时动态绑定到类 B 的方法(整数 n),这会覆盖之前的静态绑定。这是真的吗?
  • 不是“非此即彼”。是“两者”。例如,“method(Integer n)”与“method(String s)”是在编译时根据arity 确定的。 A.method() 与 B.method() 在运行时动态选择。 两个“决定”必须为要调用的六种方法之一做出,
  • 你是对的:重载是静态绑定的一个例子。 “静态方法”是另一个例子。我从来没有说过 :) 这里的重要一点是,您的代码示例说明了 Java 中的“静态”和“动态”绑定。幸运的是,我想你明白了:)

标签: java static-binding


【解决方案1】:

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

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

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

【讨论】:

  • 匹配被认为与绑定相同的签名。抱歉,我对各种术语有点陌生,但我认为绑定意味着绑定到函数实现。这应该只有在私有、静态和最终方法的情况下才有可能,对吧?这是否意味着这B 类中动态绑定到method
  • 让我先了解一下你的问题的核心......它主要与你的有关吗“有人告诉我,(静态和动态)绑定都会发生,在编译时是静态的并且在运行时动态” 评论(关于 public 实例方法)?
  • 是的,没错。我的怀疑源于绑定是一次性的想法(可能是错误的)。所以一个方法调用必须绑定到一个单一的方法实现。这是基于静态绑定与私有、静态和最终方法相关的事实(所有这些都是非常简单的案例,说明它们为何属于静态绑定示例)。重载与静态绑定的关系让我感到困惑。我同意编译器会从 A 中选择一个方法签名,但它仍然无法确定一个实现,所以我假设它不会被称为绑定。
  • @kenneth-rebello 我的理解(我可能错了)是两者都是绑定的一部分。它从适用的重载解决方案开始,包括实现选择。静态地,编译器解决重载并继续确定它可以的实现(您列出的情况:私有、静态等)。动态地,运行时为其他情况选择实现(尽管重载决议只发生在编译时)。我看到了细微差别,但我总是看到两者都包含在绑定中。
  • 是的,重载绝对可以用作静态绑定的示例。我仍然坚持认为这不是一个确定的案例。无论如何,感谢您抽出时间来回答!
【解决方案2】:

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

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

【讨论】:

    【解决方案3】:

    再一次尝试说清楚:

    重载

    重载意味着单个类有多个具有不同参数类型(又名签名)的方法,而您只是碰巧给它们取了相同的名称。如果您更改为方法的单独名称,您的程序将完全一样地工作,例如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() 还是 methodSI(),并且只决定从哪个类中获取实现。

    个人意见

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-02-05
      • 1970-01-01
      • 1970-01-01
      • 2016-03-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多