覆盖 - 参数差异

时间:2013-06-12 00:49:20

标签: java overloading

public class A{
    public static int x = 1;
    public int m(A a, B b){
        return a.m(b, b) + x;
    }
}

public class B extends A {
    public int m(A a1, B a2){
        if(a1 == a2)
            return x;
        return super.m(a1,a2);
    }
}

这是我过去考试的一个问题。

public class Main{
    public static void main(String[] args){
        B b1 = new B(){int m(A a, A b){ return 10; }};
        System.out.println(b1.m(b1, b1));
    }
}

问题是,以下输出是什么。在1的答案中我是对的。但我没有完全理解为什么。

由于B对象的内部类是(A,A)。我是否正确认为它不能覆盖超级方法m,因为它是(A,B)?如果交换了两个方法的参数,它是否能够覆盖?

既然它既不能覆盖也不能超载,它什么都不做,只是在B类中使用方法m?

对象的内部类是否仅适用于自身?它是不是一个异类?

对所有问题道歉。

提前致谢。

编辑:

从我到目前为止的理解,因为静态类型设置为B,所以类型B无法看到anon类。如果将其设置为公开,则可以看到,但仍然无法使用。

这使我对另一个问题感到困惑。

public class A{
    public static int x = 1;
    public int m(A a, B b){
        return a.m(b, b) + x;
    }
}

public class Main{
 public static void main(String[] args){
  A a1=new A();
  A a2=new A(){ 
   int m(A a,B b){
    return 10;
   }};
  B b1=new B();
  System.out.println(a1.m(a2,b1));
 }
}

调用以下内容时,输出为11。 当调用a1.m时,它传递a2和b1。

在A类中,当调用a.m(b,b)时。它调用动态类型。这是因为一旦解析它会变为动态类型吗?那么现在它可以使用anon类了吗?

4 个答案:

答案 0 :(得分:6)

让我们一起浏览JVM:

B b1 = new B(){ int m(A a,A b) { return 10; } };

这将创建B的实例,其中方法m()的匿名重载具有两个类型为A的参数。但这是一个不同的 m()方法而不是类B(或A)定义的方法,因为它们的签名({{1 }} vs A, A)不同。

然后:

A, B

这会使用System.out.println(b1.m(b1, b1)); 类型的两个参数调用b1的{​​{1}}方法。

现在JVM查找m()是什么:

  • 没有方法B有两个m()类型的参数;
  • 在班级m()中找到匹配项:名称为B的方法,其第一个参数为B(因为m()继承A)并且第二个参数类型为B;
  • A的匿名重载完全被忽略 (参见https://gist.github.com/fge/5762353
  • 方法查找结束。

因此调用类B的{​​{1}}方法。在这种方法中,我们有:

b1

由于条件为真(已使用两个参数作为完全相同的对象引用调用该方法),因此必须返回m()的值; B由班级if (a1 == a2) // TRUE! return x; 定义,班级x x

A

由于这是A类的静态成员(B类不隐藏),因此可以通过实例方法从Bextends的任何实例访问它;因此,该程序的返回码和输出为1。

答案 1 :(得分:4)

  

我认为它不能覆盖超级方法m是正确的,因为它是(A,B)?

是的,你是对的:这会创建一个重载,而不是基类中方法的覆盖

  

如果交换了两个方法的参数,是否可以覆盖?

否:要覆盖,方法签名必须完全匹配。

  

既然它既不能覆盖也不能超载,它什么都不做,只是在B类中使用方法m?

不完全是:(A, B)重载恰好比(A, A)重载更具体。

  

对象的内部类是否仅适用于自身?它是不是一个异类?

如果你传递了一对A s,你就能调用内部类中的方法。

答案 2 :(得分:1)

这里有几点:

  • 匿名内部类中的方法不是公共的,因此无法覆盖公共方法。如果必须覆盖非抽象方法,请始终使用@Override
  • b1的(静态)类型为B,因此匿名类型中声明的额外方法不可用。虽然你可以做以下事情:

    B b1 = null;
    System.out.println(new B(){int m(B a, B b){ return 10; }.m(b1, b1));
    

或者

    final B b1 = null;
    new B() {
        {
            System.out.println(this.m(b1, b1));
        }
        int m(B a, B b) { return 10; }
    };
  • 语言选择具有最具体参数(如果存在)的覆盖,而不是最不具体的参数。在前面的示例中进行了更正例如,System.err.println("donkey".toCharArray());不会调用println(Object)
  • 重写方法可以放宽返回类型,“协变返回类型”(自1.5起)。当超类型中的泛型参数类型(例如Comparable)中的参数发生时,情况不完全相同。

答案 3 :(得分:1)