有人能解释一下这次执行的结果吗?我无法注意为什么调用每个方法。我们如何区分真实类型和表观类型。谢谢:)
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
答案 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
类型匹配的最具体的。为此,重要的是引用的类型。
因此,a
为A
,因此会调用f(A)
。您的b
是B
,因此会调用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
的重载版本