【问题标题】:Overriding with object or string as argument以对象或字符串作为参数覆盖
【发布时间】:2020-05-03 18:50:25
【问题描述】:

我们期望使用该代码输出“ACBD”,但我们得到“ACBB”。为什么?

class A{
public void f(Object o){
    System.out.println("A");
}
}
class B{
   public void f(String s){
    System.out.println("B");
}
}
class C extends A{
  public void f(String s){
    System.out.println("C");
}
}
 class D extends B{
  public void f(Object o){
    System.out.println("D");
}
}
public class JavaApplication40 {
  public static void main(String[] args) {
     A a=new C(); a.f("mee");
     C c=new C(); c.f("mee");
     B b=new D(); b.f("mee");
     D d=new D(); d.f("mee");
  }
  }

我认为a必须调用A类的f,c必须调用C类的f,b必须从B类调用f,d必须从D类调用f。但是看起来它改变了函数的参数。为什么?

【问题讨论】:

  • 不同之处在于,超类 A 在函数 f 中使用 Object 作为参数,而 B 使用 String 作为参数类型。为了您对 ACBD 的期望,您需要将 B 和 D 的参数类型分别交换为 Object 和 String。

标签: java function object inheritance


【解决方案1】:

在 Java 中,方法的标识不仅与其名称相关,还与其参数集相关。也就是说,

public void f(Object o)

public void f(String s)

D 中的独立方法。 Java 根据您提供的参数类型确定在运行时执行哪一个。在此示例中,您实际上并没有覆盖任何方法,只是添加了名称相似但参数集不同的新方法。

请注意,在所有测试用例中,Java 都会选择最接近 String 的对象。如果该方法的一个版本采用String,而另一个版本采用Object,则更具体的String 将胜出。

如果您改为调用d.f(a),或使用任何其他不是字符串的对象,那么您应该看到它打印"D"。同样,如果您使用任何不是字符串的参数调用b.f(a),它应该打印"A"

【讨论】:

  • 请注意,您会得到"AC",但也会得到"BB",因为f(Object) 方法的位置(在超类或子类中)在A/C 和B/D 之间是不同的。跨度>
  • 你得到第一个“A”(所以你调用一个带有 Object 参数的方法),虽然存储在 a 变量中的 C 实例有这两种方法,按照你的逻辑它应该打印“C”(我在回答中解释了这种行为)。
  • 但是字符串也是对象。为什么要调用以 String 作为参数?
【解决方案2】:

由于D 类扩展A 类,并且您将String 作为参数传递,它将采用与d.f("mee") 中的输入匹配的参数的方法 - 即public void f(String s)

另一方面,如果在“D”类中的函数不是public void f(Object o),而是public void f(String s),您将在日志中得到"D"作为输出。

【讨论】:

    【解决方案3】:

    重载和覆盖是有区别的。在您的代码中,您使用重载方法(创建具有相同名称但参数类型不同的方法)。重载由编译器在编译时解决(与覆盖不同,在运行时解决)。

    对于a,编译器看到它的类型是A,所以选择A方法。

    对于c,编译器看到它的类型是C,所以选择签名最具体的方法,也就是C方法(String比Object更具体)。

    对于b,编译器看到它的类型是B,所以选择B方法。

    对于d,编译器看到它的类型是D,所以选择签名最具体的方法,也就是B方法(String比Object更具体)。

    【讨论】:

      【解决方案4】:

      您的参数"mee" 最接近String 而不是Object,因此,

      public void f(String s){
          System.out.println("B");
      }
      

      被选中

      public void f(Object o){
          System.out.println("D");
      }
      

      如果您期望ACBB,则需要将D 定义为

      class D extends B{
        public void f(String s){
          System.out.println("D");
      }
      

      【讨论】:

      • 是的,这是有道理的。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-07
      • 2015-07-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多