java中的向下广播+;使用变量参数调用方法
当我调用java中的向下广播+;使用变量参数调用方法,java,variadic-functions,downcast,Java,Variadic Functions,Downcast,当我调用a.displayName(“Test”)时,它调用了Icecream类的方法displayName(String…s)方法接受变量参数。 输出- 但是,当我将方法更改为displayName(strings)(我已经注释掉了代码中的那一部分)时,它会调用类Faloodeh的方法。 新产量- test Faloodeh test Faloodeh test Faloodeh: Faloodeh test Faloodeh: Faloodeh 我想知道为什么会这样 class I
a.displayName(“Test”)
时,它调用了Icecream类的方法displayName(String…s)
方法接受变量参数。
输出-
但是,当我将方法更改为displayName(strings)
(我已经注释掉了代码中的那一部分)时,它会调用类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)
会导致Faloodeh
中的displayName(String s)
方法重写其超类中的方法
Icecream.displayName(String…s)
和Faloodeh.displayName(String s)
具有不同的签名,因此它们不会相互覆盖。但是将前者更改为接受一个字符串只会导致它们具有相同的签名,从而导致发生重写
在Java中,方法调用大致分为三个步骤来解决(有关更多信息,我还详细解释了):
查找类以搜索适用的方法。这是基于调用方法的对象的编译时类型。在这种情况下,a
a
的编译时类型是Icecream
,因此只考虑Icecream
的方法。请注意,它在Faloodeh
中找不到displayName
方法,因为a
的编译时类型是Icecream
根据传递的参数确定要调用的方法重载。这里只有一个选择。在更改之前和之后,displayName
是唯一与您传递的参数兼容的重载
根据调用方法的对象的运行时类型,确定要调用的方法实现a
的运行时类型为Faloodeh
。在更改之前,displayName
在Faloodeh
中没有被覆盖,因此它调用超类实现。更改后,displayName
被覆盖,因此调用Faloodeh
中的实现
关于您的编辑:
在这种情况下,由于b
的编译时类型是Faloodeh
,因此要搜索的类是Faloodeh
(步骤1)。但是,有两种方法与您给出的参数相匹配(步骤2):
displayName(String…
,在Faloodeh
中声明,以及李>
displayName(String)
它是继承的
在这种情况下,编译器总是支持不带变量arity的重载-displayName(String)
。这一点在本文件中有明确规定。特别是,步骤2进一步分为三个子步骤。第一个子步骤尝试在不允许变量arity方法的情况下找到方法,如果任何子步骤找到任何方法,则跳过其余子步骤。您的测试似乎表明您对多态性很感兴趣。因此,您可能知道,在Java中,我们可以说您的对象具有两种类型:
- 静态类型:基于变量的声明:
Icecream A=…
。对象a的编译(即静态)类型为Icecream
- 动态类:基于此变量的矫揉造作:
。。。a=新的Faloodeh()
李>
当编写代码时,假设您只使用静态类型。这意味着编译器知道您可以使用的类/字段/方法,并允许您使用它们。这就是您可以编写如下代码的原因:
Icecream a = new Icecream();
a.displayName("test");
而且不会写:
Icecream a = new Icecream();
a.unknownMethod("test");
编译器知道您的类Icecream有一个名为displayName
的方法,该方法采用var arg。它还知道有一个Faloodeh
类。编译器知道这个类可以有自己的方法和字段,也可以访问其父类的方法和字段
Faloodeh b = new Faloodeh();
b.displayName("test");
因此,基本上,当您在类中声明和实现一个方法时,它的子类可以通过重新实现该方法来重写行为。这就是您使用方法void descripe(字符串s)
所做的
但是方法displayName
很棘手,因为您以相同的方式调用它,但实际上,它们并不相同,因为它们都使用arg。让我们试着成为一名编译器。我编译了你们的两个类,这里是我创建的:
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…
,而不是displayName(String)
?因为,在静态情况下,编译器看到您正在使用Icecream类型调用displayName
方法,并且在动态情况下,只有一个方法displayName带有varargs,所以Faloodeh从未重写过该方法。因此,您可以直接调用IcecreamdisplayName
方法
如果在Icecream中取消注释方法displayName(String)
,则Faloodeh将接管,因为动态地,Faloodeh在displayName(String)
上有自己的实现,这就是它被调用的原因
希望能有帮助。有关多态性的更多信息:
**编辑**
这几乎是相同的原因。两个类都有一个静态方法displayName(String)
,另一个类有displayName(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
Icecream a = new Faloodeh()
a.displayName("test", "test");