Java继承:向上转换子类

Java继承:向上转换子类,java,inheritance,casting,upcasting,Java,Inheritance,Casting,Upcasting,我已经阅读了文档和其他问题,但有一些向上转换的案例确实让我感到困惑 我举了这个例子,虽然前3个案例经过一点思考后非常简单,但最后4个案例让我感到困惑 很明显,我对演员阵容有些不了解 class A { public static void p (Object o) { System.out.println(o); } public void m1 (A a) { p("m1(A) in A"); } public v

我已经阅读了文档和其他问题,但有一些向上转换的案例确实让我感到困惑

我举了这个例子,虽然前3个案例经过一点思考后非常简单,但最后4个案例让我感到困惑

很明显,我对演员阵容有些不了解

class A {
    public static   void p (Object o)   { System.out.println(o); }
    public          void m1 (A a)       { p("m1(A) in A"); }
    public          void m1 ()          { m1(new B());}
    public          void m2 (A a)       { p("m2(A) in A");}
    public          void m2 ()          { m2(this);}
    public          void m3 (B b)       { m2(this); }
}

class B extends A {
    public          void m1 (B b)       { p("m1(B) in B");}
    public          void m2 (A a)       { p("m2(A) in B");}
    public          void m2 (B b)       { p("m2(B) in B");}
    public          void m3 (B b)       { super.m1(b);}
}

public class Main {
    public static void main(String[] args) {
        A a = new B(); // Instance of class B casted to A
        B b = new B(); // Instance of class B

        // 1. prints "m1(A) in A"
        b.m1();

        // 2. prints "m2(A) in B"
        b.m2();

        // 3. prints "m2(A) in B"
        a.m2();

        // 4. prints "m1(A) in A"
        a.m3((B)a);
    }
}
例1:

我希望这里能打印出B中的m1(B)

B继承A,因为没有
B.m1()
,它调用
A.m1()
,后者调用
m1(B)
。既然我们是从B调用,为什么它调用
A.m1(B)
,而不是
B.m1(B)

我期望A.m1()->B.m1(A),而不是A.m1()->A.m1(B)

例2:

因为4在一个“中给出了
”m1(A),所以我在这里也期望得到同样的结果,因为对我来说,流程似乎是一样的

看看示例1,我期望A.m2()->A.m2(A),而不是A.m2()->B.m2(A)

例3:

bb.m2()在B中打印
m2(A)

我希望m2(A)在A中是
m2(A),因为A被铸造成
A
。为什么它调用
B.m2(A)

例4


它调用
B.m3()
,如果它强制转换为
A
。为什么?我希望它调用
A.m3()
,因为它已经被浇铸了示例1:调用
m1(新的B())在类
A
A
不知道子类的任何实现细节(例如
B
),因此它只知道
A.m1(A)

示例2:您可以添加一个简单的
System.out.println(this.getClass())
显示此
的类。它将显示
的类型为
$B
。您在
B
上调用了该方法,并且
B
知道该方法
m2(B)
,因此调用了一个方法。
例3:与例5的原因相同。
示例4:它被称为
B.m3()
,后者依次调用
super.m1(B)。这将调用super方法
A.m1(A)
,因为
B
扩展了
A
。它无法调用
B.m1(B)
,因为它显式地调用了
super
。如果
A
中没有足够的方法,您将得到一个编译器错误

更新

示例1和示例2之间的差异:
在例1中
b.m1()
正在调用类
A
的方法
m1()。因为在调用
m1()
时,编译器只知道类型是
A
,而不是
B
。假设您只能看到
a
类型的变量,那么您只能看到
a
的方法。因此,随后调用
m1(new B())
导致调用
A
方法。没有
B
可供编译器调用它的方法。

示例2中
b
类型的变量
b
,因此编译器可以查看
A
的所有方法和
b
的所有方法。正因为如此,编译器知道方法
B.m2(B B)
,并且可以在随后的
m2(this)

调用中调用它。您能否更具体地说明问题本身,您对它感到困惑的是什么,以及为什么?不仅仅是在代码中的注释中。@Stultuske你是对的,我还单独添加了问题,试图进一步解释它们。这很长,而且有点难理解。我建议您删除所有您已经理解的内容,只留下您想要解释的代码部分,以及一点您自己的推理。除此之外,你问的问题还不错。@CoffeeNinja完成了,简化了,并试图让它变得更清晰。这是一个很好的问题,关于继承容易被误解的事情。例如,下面提交的唯一答案(以及投票结果)是错误的。虽然我写了另一个答案,但我不能提交,因为它很快就被搁置了。对不起,我仍然不知道4之间的区别。五,。我怎么知道4在类A中被调用,而5和6在类B中被调用?虽然m1(新的B())确实在类A中被调用,但B的重写方法仍然是首选的,而不是A的原始方法。A中的
this
的类型。m1()实际上是B(在示例1中)