Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java中的向下广播+;使用变量参数调用方法_Java_Variadic Functions_Downcast - Fatal编程技术网

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从未重写过该方法。因此,您可以直接调用Icecream
    displayName
    方法

    如果在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");