[当我调用a.displayName("Test")
时,它将调用Icecream类的方法。 displayName(String...s)
方法采用可变参数。输出-
test Icecream
test Faloodeh
test Faloodeh: Faloodeh
test Faloodeh: Faloodeh
但是当我将方法更改为displayName(String s)
(我已在代码中注释掉该部分)时,它将调用Faloodeh类的方法。新输出-
test Faloodeh
test Faloodeh
test Faloodeh: Faloodeh
test Faloodeh: Faloodeh
我想知道为什么会这样。
class Icecream{
public void displayName(String...s){
System.out.println(s[0]+" "+"Icecream");
}
/*public void displayName(String s){
System.out.println(s+" "+"Icecream");
}
*/
public void describe(String s) {
System.out.println(s+" "+"Icecream: Ice cream");
}
}
class Faloodeh extends Icecream {
public void displayName (String s){
System.out.println(s+" "+"Faloodeh ");
}
public void describe (String s) {
System.out.println(s+" "+"Faloodeh: Faloodeh");
}
}
class Test {
public static void main(String arg[]) {
Icecream a=new Faloodeh ();
Faloodeh b=( Faloodeh)a;
a.displayName("test");
b.displayName("test");
a.describe("test");
b.describe("test");
}
}
**编辑-**感谢您的回答。如有其他疑问,请帮助我。我将代码更改为-
class Icecream{
public void displayName(String s){
System.out.println(s+" "+"Icecream");
}
/*public void displayName(String s){
System.out.println(s+" "+"Icecream");
}
*/
public void describe(String s) {
System.out.println(s+" "+"Icecream: Ice cream");
}
}
class Faloodeh extends Icecream {
public void displayName (String...s){
System.out.println(s+" "+"Faloodeh ");
}
public void describe (String s) {
System.out.println(s+" "+"Faloodeh: Faloodeh");
}
}
class Test {
public static void main(String arg[]) {
Icecream a=new Faloodeh ();
Faloodeh b=( Faloodeh)a;
a.displayName("test");
b.displayName("test");
a.describe("test");
b.describe("test");
}
}
现在这给出以下输出-
test Icecream
test Icecream
test Faloodeh: Faloodeh
test Faloodeh: Faloodeh
正如大家所解释的,这里b是Faloodeh类的对象。 Faloodeh类的displayName(String...s)
不会被覆盖。仍在输出中,它显示test Icecream
为什么这样?
这里的关键是将displayName(String... s)
更改为displayName(String s)
会导致displayName(String s)
中的Faloodeh
方法其超类中的方法。
Icecream.displayName(String... s)
和Faloodeh.displayName(String s)
具有不同的签名,因此它们不会相互覆盖。但是将前者更改为接受一个String
仅会导致它们具有相同的签名,这会导致覆盖。在Java中,方法调用大致可通过三个步骤来解决(有关更多信息:JLS §15.12,我也将更详细地解释here):
a
。 a
的编译时间类型为Icecream
,因此仅考虑Icecream
的方法。请注意,由于displayName
的编译时间类型为Faloodeh
,因此在a
中找不到Icecream
方法。displayName
是唯一与您传递的参数兼容的重载。a
的运行时类型为Faloodeh
。更改之前,displayName
不会在Faloodeh
中被覆盖,因此它将调用超类实现。更改之后,displayName
被覆盖,因此调用了Faloodeh
中的实现。在这种情况下,由于b
的编译时间类型为Faloodeh
,因此要搜索的类别为Faloodeh
(步骤1)。但是,有两种方法与您提供的参数匹配(步骤2):
displayName(String...)
中声明的[Faloodeh
,和;始终支持无变量Arity的重载
displayName(String)
。这在displayName(String)
中有明确规定。特别是,步骤2进一步分为三个子步骤。第一个子步骤尝试查找不允许使用可变Arity方法的方法,如果任何子步骤找到任何方法,那么将跳过其余的子步骤。Icecream a = ...
。Icecream
。 writing
... a = new Faloodeh()
而且不能写:
Icecream a = new Icecream(); a.displayName("test");
编译器知道您的Icecream类具有一个名为Icecream a = new Icecream(); a.unknownMethod("test");
的方法,该方法采用var-arg。它还知道存在displayName
类。编译器知道此类可以具有自己的方法和字段,并且可以访问其父级的方法和字段。
Faloodeh
因此,基本上,当您在类中声明并实现方法时,其子级可以通过重新实现该方法来覆盖行为。这是您使用方法Faloodeh b = new Faloodeh(); b.displayName("test");
执行的操作。但是方法
void describe(String s)
是棘手的,因为您以相同的方式调用它,但是实际上,由于它们都使用了arg,因此它们并不相同。让我们尝试成为一个编译器。我编译了您的两个类,在这里创建了我创建的内容:
displayName
现在,在运行代码时,让我们看看将使用主行中的行真正调用哪些方法:
Icecream => displayName | varargs Icecream => describe | String Fadooleh => displayName | String Faloodeh => describe | String
为什么第一行调用方法Icecream a = new Faloodeh(); Faloodeh b = (Faloodeh)a; a.displayName("test"); => Icecram => displayName | varargs b.displayName("test"); => Fadooleh => displayName | String a.describe("test"); => Faloodeh => describe | String b.describe("test"); => Faloodeh => describe | String
而不是displayName(String...)
?因为从静态上看,编译器看到您使用的是Icecream类型来调用displayName(String)
方法,并且动态地,只有一个带有varargs的方法displayName,此方法从未被Faloodeh覆盖。因此,您可以直接调用IcecreamdisplayName
方法。如果您在Icecream中取消注释方法
displayName
,那么您将让Faloodeh接管,因为动态地,Faloodeh在displayName(String s)
上有其自己的实现,这就是调用它的原因。
希望有帮助。有关多态的更多信息:displayName(String)
**编辑**这几乎是相同的原因。您的两个类都静态具有方法https://www.tutorialspoint.com/java/java_polymorphism.htm,另一个类具有displayName(String)
。
[使用displayName(String...)
时,它将首先与b.displayName("test")
匹配,仅在您的displayName(String)
对象中实现。因此,行为。
例如,这将是不可能的:
Icecream
因为Icecream a = new Faloodeh() a.displayName("test", "test");
对名为Icecream
的方法一无所知。