【问题标题】:Understanding Java Inheritance了解 Java 继承
【发布时间】:2012-04-10 21:10:39
【问题描述】:

给定以下 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

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

感谢您的宝贵时间

【问题讨论】:

    标签: java inheritance compiler-construction polymorphism


    【解决方案1】:

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

    但是,它可以通过对 B 的引用来调用。

    【讨论】:

      【解决方案2】:

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

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

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

      a1.m1( (A)b1 )
      

      这告诉编译器你试图调用哪个方法。

      【讨论】:

        【解决方案3】:

        只要按照代码:

        区块 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 之外为 "m1(B) in B" ,只需将 A 类中的方法标记为虚拟方法并在 B 类中覆盖相同的方法。

        【讨论】:

          【解决方案4】:

          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 在此上下文中所关心的全部内容,它不关心您从什么创建对象,只关心它是什么。

          【讨论】:

          • 另外,顺便说一句,您是否打算为每个对象设置一个toString 方法,然后将该对象传递给您的p(Object o) 方法
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-23
          • 2014-02-22
          • 1970-01-01
          • 2016-10-31
          • 1970-01-01
          相关资源
          最近更新 更多