使用派生类实例化基类?

时间:2014-09-17 18:32:27

标签: java inheritance polymorphism

这是我的代码,我无法推断为什么输出会像那样。如果有人能解释请。

import java.io.*;
class b {
void m(b a){
System.out.println(" b");
}  
}
class bcd extends b {
    void m(bcd a){
System.out.println("bcd");
 }  
}
class cde extends bcd {
void m(cde a){
System.out.println("cde");
}  
}
public class ABC{
public static void main(String[] args){
b ob1= new cde();
cde ob2=new cde();
ob1.m(ob2);
}
}

2 个答案:

答案 0 :(得分:1)

在您的示例中,将调用b类中的方法。我想你想显示重写或重载的例子,但这不是重写而不是重载。

用于覆盖使用后期绑定。在这种情况下,知道方法签名后,虚拟机会分析调用此方法的实例化(实际)类型的对象,以准确确定要调用的方法定义的类。 对于重载使用早期绑定。在这种情况下,编译器检查正式类型的对象

很好的例子解释了覆盖或重载:

public class Test{

    public static class Parent{

        public void test(){
            System.out.println("parent class");
        }
    }

    public static class Child extends Parent{

        public void test(){
            System.out.println("child class");
        }
    }

    public static class Tester{

        public void test(Parent obj){
            System.out.println("Parent method");
            obj.test();
        }

        public void test(Child obj){
            System.out.println("Child method");
            obj.test();
        }
    }

    public static void main(String[] args){
        Parent obj = new Child();
        Tester t = new Tester();
        t.test(obj);
    }
}

结果执行:

  

父方法

     

儿童班

修改 1)编译器不查看类型参数。它根据调用它的实际类型对象确定调用的方法:对于你的例子,这是b类,对于我的例子,这是Tester类.2)如果我们在一个具有相同名称的类中有两个方法,但是方法中的不同类型参数(重载),然后java虚拟机查看类型参数(在我的例子中如何:两个方法具有相同的名称,但传输类Parent的对象和使用Parent参数的调用方法)

在你的例子中,如果是这样的话:

class B {
   void m(B a){
          System.out.println(" b");
   }  

   void m(Cde a){
         System.out.println("cde");
   }  
}

public class ABC{
       public static void main(String[] args){
          B ob1= new Cde();
          Cde ob2=new Cde();
          ob1.m(ob2);
       }
}

这是重载示例,将调用void m(cde a)

<强> EDIT2: 是的,你的ob1对象是实例cde,但java虚拟机只检查实例化(真实)类型的对象,以防覆盖(当两个类中的方法签名相同时)。所以,你需要记住两个覆盖和重载的东西,在其他情况下编译器查看正式类型引用,在你的例子中这是b。

但最重要的是有趣的事情。

来自http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.4.5

  

如果相反,则返回类型可能会因为相互覆盖的方法而异   返回类型是引用类型。的概念   return-type-substitutability支持协变返回,即   将返回类型专门化为子类型。

A method declaration d1 with return type R1 is return-type-substitutable for another method d2 with return type R2,
     

当且仅当满足以下条件时:

    If R1 is void then R2 is void.

    If R1 is a primitive type, then R2 is identical to R1.

    If R1 is a reference type then:

        R1 is either a subtype of R2 or R1 can be converted to a subtype of R2 by unchecked conversion (§5.1.9), or

        R1 = |R2|

如果您的代码具有不同的返回类型,但参数相同,那么它也将是示例覆盖:

class Bcd extends B {
    @Override
    Bcd m(Cde a) {
        System.out.println("bcd");
        return a;
    }
}

class Cde extends Bcd {
    @Override
    Cde m(Cde a) {
        System.out.println("cde");
        return a;
    }
}

class B {
    B m(Cde a) {
        System.out.println("b");
        return a;
    }
}

class Test {

    public static void main(String[] args) {
        final B ob1 = new Cde();
        final Cde ob2 = new Cde();
        ob1.m(ob2);
    }
}

结果:

  

CDE

因为这也是最重要的。

答案 1 :(得分:0)

当您调用ob1.m(ob2);时,将调用类b的方法。 类

中定义的方法
class bcd extends b {
    void m(bcd a) {
        System.out.println("bcd");
    }
}

class cde extends bcd {
    void m(cde a) {
        System.out.println("cde");
    }
}

是重载方法而不是覆盖方法。