Java中的动态类型转换任务

3

在大学里,我们被赋予了一个Java程序,并任务是理解输出的方式。该程序如下:

interface A {
    public void f(A x);
}

interface AA extends A {
    public void f(B x);
}

class B implements A {
    public void f (A x) {System.out.println("1");}
    public void f (B x) {System.out.println("2");}
    public void f (C x) {System.out.println("3");}
}

class C implements A,AA {
    public void f(A x) {System.out.println("4");}
    public void f(B x) {System.out.println("5");}
    public void f(C x) {System.out.println("6");}
}

public class Task7 {
    public static void main(String[] args) {
        B b = new B();  C c = new C();
        A ac = c;       A ab = b;
        AA aac = c;

        b.f(b);         c.f(c);
        ac.f(b);        ab.f(b);
        aac.f(b);       aac.f(c);
    }
}

输出结果为“264154”。我不太明白最后4个数字的含义,有人能帮忙解释一下吗?
编辑:进一步解释我的问题: 'b.f(b)' 显然会打印出2,因为你将一个B对象的引用给了一个B引用,而 'c.f(c)' 出于同样的原因将打印6。
'ab.f(b)' 将调用 'b.f(b)',因为它的动态类型是B。现在,我不明白为什么之前被同一个类视为'B'的参数 'b' 现在被理解为'A',以至于打印出了 "1" 而不是 "2"。对于其他方法调用也是同样的情况,我只是不明白为什么相同的参数和相同的基础对象会被不同地解释。

我们不会解决你的作业。你能缩小一下造成困惑的原因吗? - C-Otto
@C-Otto 是的,问题似乎在于前两个方法调用中它们看到了各自类别的对象,而在后面四个方法调用中,它们有时被视为它们的类别,有时被视为它们的接口。但我不知道为什么,我希望有人能解释一下,因为在我的大学脚本和互联网上都找不到答案。 - ddominnik
我本来期望的输出结果是"265256"。 - ddominnik
@ddominnik,你听说过多态性吗? - Alex Cuadrón
@AndrewTobilko 我已经更新了原始帖子,提供了关于我的问题的更多信息。 - ddominnik
2个回答

3

多态仅适用于左侧的对象.。编译器在编译时确定要调用哪个方法签名,而不管传递的值是什么。

例如:

B b = new B();
b.f((A) null);
b.f((B) null);
b.f((C) null);

在编译时仅知道引用类型的情况下,将123打印出来。

同样地,当调用静态方法时,如果使用引用,则仅引用类型有关。

Thread t = null;
t.yield(); // call Thread.yield() so no NullPointerException.

我不明白为什么相同的参数和相同的基础对象会被解释成不同的结果。

方法签名是根据引用类型在编译时确定的。

另一种看待这个问题的方式是,多态只适用于被覆盖的方法,而不适用于重载的方法。


@ddominnik,我认为设计师们认为将多态性限制在左参数上更简单,因此你所建议的可能无法实现。 - Peter Lawrey

1

首先,你必须真正理解多态性。

我不打算解释为什么会打印出前两个值,但我认为了解其他情况的输出原因很有趣。

那么,让我们来看第三个: ac.f(b); ac 是 A 类的一个实例:A ac = c; 而 c 是 C 类的实例:C c = new C();。 因此,A ac = new C(); 这意味着 ac 只能使用 C 类中的函数,并且在这些函数中,它只能调用写在 A 接口中的函数:public void f(A x) {System.out.println("4");}(编译器不关心参数部分对象的类型)

另一个例子: ab.f(b); 这是输出中的第四个数字。 ab 是 A 的一个实例: A ab = b,b 是 B 的一个实例: B b = new B();。因此,A ab = new B();。这意味着 ab 可以调用在 B 中声明的所有函数在 A 中声明的函数,因此: public void f (A x) {System.out.println("1");}。(请记住,它们必须在两个部分中都声明,而不仅仅是一个部分)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接