2013-06-12 39 views
3
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)); 
    } 
} 

问题是,下面的输出是什么。我的答案是正确的,但我没有完全明白为什么。

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

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

对象的内部类是否仅为其自身工作?它是否像一个匿名课?

对所有问题表示歉意。

在此先感谢。

编辑:

从我的理解,到目前为止,其因为静态类型设置为B,那么B型是无法看到匿名类。如果这是公开的,它可以被看到,但它仍然不会被使用。

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

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)时。它调用动态类型。这是因为它一旦解析就更改为动态类型?那么现在它能够使用匿名类吗?

+0

回答如下,请告诉我,如果事情是模糊的。这是颇有些运动在这里;) – fge

回答

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)中的参数不完全相同。
+0

谢谢,这帮助了我。但提出了另一个问题。我在原帖的末尾编辑过。 – user2469515

+0

@ user2469515重载是在编译时静态地在变量的静态类型上完成的。当方法执行时,变量正好指向的类型将被覆盖。有些语言允许在多种类型(多派遣,或者只是双派遣)上进行动态分派,但也存在一些问题。 –

+0

感谢您的帮助 – user2469515

6

让我们走过的JVM:

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

这具有A类型的两个参数方法m()的匿名过载造成的B一个实例。但是,这是一个不同m()方法比类B(或A)定义,因为他们签名A, A VS A, B)不同。

然后:

System.out.println(b1.m(b1, b1)); 

这要求b1m()方法与B类型的两个参数。

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

  • 没有方法有B类型的两个参数m();
  • B类,它找到一个匹配:由名称m()它的第一个参数是一个A(因为B继承A),并且是B类型的第二个参数的方法;
  • b1匿名重载是完全忽略这里!(参见https://gist.github.com/fge/5762353
  • 方法查找结束。

因此调用B类的m()方法。而在这个方法中,我们有:

if (a1 == a2) // TRUE! 
    return x; 

由于条件为真(该方法被调用的两个参数是完全相同的对象引用),必须返回的x价值;

public static int x = 1; 

由于这是类A(其中B类不隐藏)它是由实例方法同样可访问的,从任何实例的静态构件:和xA类,这类Bextends定义AB;因此,该程序的返回代码和输出为1.

+0

它不是在匿名内部类中定义的方法寻找,因为(静态)类型b1'的''是B'。 –

+0

否。尝试使用'm()'的匿名重载的示例代码,它有两个类型为'B'的参数而不是'A':返回的值为10!因为'B,B'更具体,'A,B';但在这里,超载是'A,A',它是_less_特定的。 – fge

+0

如果是这样,我认为在javac中有一个错误。 (我没有我自己的机器上安装了Java。) –

4

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

是的,你是正确的:这将创建一个超载,不是重写基类中的方法的

如果两个方法的参数交换,它能重写吗?

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

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

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

该对象的内部类是否仅适用于自己?它是否像一个匿名课?

你将能够在内部类中调用该方法,如果你通过了一对A s。