Java中的继承,表观类型与实际类型

时间:2015-06-07 20:12:14

标签: java inheritance types extends

有人能解释一下这次执行的结果吗?我无法注意为什么调用每个方法。我们如何区分真实类型和表观类型。谢谢:)

public class JavaApplication15 {
   public static void main(String[] args) {
       A a = new A();
       B b= new B();
       A ab = new B();
       b.f(a);
       b.f(b);
       b.f(ab);
  }  
}

public class A {
   private final String id="A";
   public void f(A x){
     System.out.println("Send a fax to "+ x ) ;
  }
  public String toString(){return id;}
}

public class B extends A{
   private final String id="B";
   public void f(B x){
     System.out.println("Send an email to"+ x ) ;
   }
   public String toString(){return id;}
}

结果:

Send a fax to A
Send an email to B
Send a fax to B

4 个答案:

答案 0 :(得分:3)

你是overloading(根据维基百科)创建多个具有不同实现的同名方法。我认为你的意思是使用f(A x)方法override f(B x)方法。覆盖(根据维基百科)允许子类或子类提供已由其某个超类或父类提供的方法的特定实现。

基于你问题中表达的惊喜,我认为你想要像

这样的东西
@Override
public void f(A x) {
  System.out.println("Send an email to"+ x ) ;
}

答案 1 :(得分:2)

@Override
public String toString()
{
    return id;
}

这定义了类的输出方式。当您调用如下函数时:

b.f(a)

您正在输入一个类作为参数。由于您的toString()方法覆盖了输出课程的标准方法,因此您会在id之后显示Send an email to

答案 2 :(得分:2)

班级B的对象包含f(A)f(B)。当您致电f(x)时,它通常会选择与x类型匹配的最具体的。为此,重要的是引用的类型

因此,aA,因此会调用f(A)。您的bB,因此会调用f(B)。但你的ab是什么?引用的类型是A。所以编译器告诉它调用f(A)重载。

但是,它不应该将ab对象用作A,因此使用send a fax to A而不是A.toString()打印B.toString()

不,因为在这种情况下要调用的方法的选择不是由参数决定的。如上所述,它不是重载之间的选择,它是覆盖之间的选择。在决定使用哪个方法时,来自超类的方法或来自子类的方法,对象的实际类型决定它。由于ab引用的对象实际上是B,因此选择了toString()的{​​{1}}。

所以 - 在重载方法中,所选择的方法是根据参数的数量和类型确定的,参数的类型是引用的类型< / em>的

重写的方法中,所选择的方法是对象实例的实际类型中的方法,无论调用它的引用类型如何。

请注意,如果某个方法与父方法具有相同的名称,参数数量和相应的参数类型,则该方法仅被视为重写

答案 3 :(得分:1)

由于B扩展A而A有公共方法。所以它有以下两种方法 -

public void f(A x){
     System.out.println("Send a fax to "+ x ) ;
} 

和 -

public void f(B x){
     System.out.println("Send an email to"+ x ) ;
}

实际上B中的seond方法是从void f(A x)

继承的方法A的重载版本