理解Java继承

问题描述 投票:0回答:4

给出以下 Java 代码:

class mainul {

    public static void main(String[] args) {

    /*block 1*/
        B b1 = new B();
        A a1 = b1;
        a1.m1(b1);

    /*block 2*/
        B b2 = new B();
        B a2 = b2;
        b2.m1(a2);
    }
}

class A {

    public static void p(Object o) {
        System.out.println(o.toString());
    }

    public void m1(A a) {
        p("m1(A) in A");

    }
}

class B extends A {

    public void m1(B b) {
        p("m1(B) in B");
    }
}

有人可以解释为什么这个程序的输出是

m1(A) in A
m1(B) in B

人们会期望块 1 的输出是“B 中的 m1(B)”,因为 a1 的动态类型是 B。我注意到 m1 的 A 和 B 中的函数签名不匹配(人们期望A 类型的对象和 B 类型的另一个作为其参数),并且 A 中的方法似乎获得优先级,但无法真正将其链接到我的输出,因为它似乎与 block2 的输出不一致。

感谢您的宝贵时间

java inheritance polymorphism
4个回答
7
投票

正如您所注意到的,

B.m1(B)
不会覆盖
A.m1(A)
,因为它们采用不同的参数(尝试添加
@Override
注释,您会看到编译器抱怨)。 所以永远不能通过对
A
的引用来调用它。

但是,可以通过对

B
的引用来调用它。


1
投票

被调用的方法是在编译时设置的(在本例中为 A.m1(A))。 我知道你认为它是动态的,对吗? 动态绑定是运行时绑定。 嗯,是的,但它仅对 A.m1(A) 上的方法是动态的。 因此 A 的任何子类都可以提供替代实现,但其签名必须相同,否则这是一个重载方法,而不是同一个方法。

这也意味着动态绑定不会考虑调用中使用的参数。 方法名称和正式签名在编译时设置。 改变类型就不是同一个方法,不会被调用。

您可以这样做来强制编译器查看该方法:

a1.m1( (A)b1 )

这告诉编译器您正在尝试调用哪个方法。


1
投票

只需按照代码操作即可:

区块1

B b1 = new B();   //- variable  b1 (type is B) points to instance of B() 

A a1 = b1;        //- variable  a1 (type is A) points to instance of B() .. same as b1 is
                  // pointing to.

 a1.m1(b1);       // Call Method m1 on a1 (i.e. of class A ) ..IMP catch > as a1 holds
                  // object of b1, if there is method in Class A which is overriden in B,
                  // call that overriden method. But here method m1() is not overriden 
                  // by B  it will call method of class A.

区块2

B b2 = new B();  // variable b2 (type B) points to instance of B()

B a2 = b2;       // variable a2 (type B) points to same instance as b2 is pointing to.

b2.m1(a2);       // call method m1 of b2 (of class B). There is only one method m1 in b2
                 // and b2 holds object of B, it must call method of class B

另外,如果您希望块 1 之外的内容成为“B 中的 m1(B)”,只需将 A 类中的方法标记为虚拟方法并覆盖 B 类中的相同方法即可。


0
投票

正如 Oli 所说,这两个方法签名不同。

当你给他们每个人打电话时:

    B b1 = new B();
    A a1 = b1;
    a1.m1(b1);

    /*block 2*/
    B b2 = new B();
    B a2 = b2;
    b2.m1(a2);

首先传递一个 A 类型的对象,然后传递一个 B 类型的对象。这就是 Java 在此上下文中所关心的一切,它不关心你从什么创建对象,只关心它是什么。

© www.soinside.com 2019 - 2024. All rights reserved.