【问题标题】:Why is the return type of method not included in the method-signature?为什么方法的返回类型不包含在方法签名中?
【发布时间】:2021-07-05 12:22:59
【问题描述】:

为什么方法的返回类型不包含在签名中?

一个例子

public void method1(String arg){...}

public String method1(String arg){...}

这会导致错误。

【问题讨论】:

    标签: java


    【解决方案1】:

    这样做是因为编译器无法找出所有上下文中的重载。

    例如,如果您调用

    String x = method1("aaa");
    

    编译器知道您正在寻找第二个重载。但是,如果您调用

    method1("aaa");
    

    像这样,编译器不知道你想调用这两个方法中的哪一个,因为调用返回String的方法并丢弃结果是可以的。为避免此类歧义,Java 禁止仅在返回类型上有所不同的重载。

    【讨论】:

      【解决方案2】:

      由于您的问题在标题中没有涉及任何特定的编程语言(我知道它在标签中涉及),所以我将分享我最近使用 Swift 的经验。 在 Swift 中,函数/方法签名实际上包括返回类型。所以编译器只有在你调用这个函数/方法而没有明确指定返回类型时才会抛出错误,例如:

      func some() -> Bool {
          return true;
      }
      
      func some() -> Int {
          return 1;
      }
      
      let valBool: Bool = some()
      let valInt: Int = some()
      
      // this doesn't work: Ambiguous use of 'some'
      some()
      

      在这个 Swift 之上甚至使它更有趣。它允许您拥有 2 个具有相同参数的函数/方法,并且仅当参数名称不同时才返回类型,例如:

      func some(#foo: Bool) -> Bool {
          return foo;
      }
      
      func some(#bar: Bool) -> Bool {
          return bar;
      }
      
      some(foo: true)
      some(bar: false)
      

      因此它在方法签名中为您提供语义区分

      UPD。由于 Swift 2.0 的外部参数名称已更改,现在您必须提供两次外部和本地名称,即使它们相同

      func some(foo foo: Bool) -> Bool {
          return foo;
      }
      
      func some(bar bar: Bool) -> Bool {
          return bar;
      }
      
      some(foo: true)
      some(bar: false)
      

      【讨论】:

      • +1 以获得更广泛的 java 视角。听听您对获得的便利是否超过与此选择相关的问题的意见会很有趣。我猜对于简单的返回类型并不重要,但是对于对象,这可以允许重用输出变量资源......然后不要让你轻易忽略返回值,我认为这是一个功能而不是麻烦。
      【解决方案3】:

      你不能只在它的返回类型上重载一个方法。这简直是​​非法的。让我们暂时假设使用返回类型重载方法是合法的,并且您定义了两个method1 方法。现在我们要调用返回String object

      String string = method1(sth);

      JVM理论上可以识别你想要调用的方法,但是这样的调用呢:

      method1(sth);

      正如您所见,这两种方法都可以被调用,并且这样的操作是明确的。 JVM 不知道它应该调用哪个方法。这就是禁止这种重载的原因。

      【讨论】:

      • 你不能因为你不能?真的吗?
      • 我在编辑中解释了这一点;)我提交了简短的帖子,因为写下这些简单问题的答案就像一场比赛,所以如果你可以的话,请取消你的投票。
      • 我告诉过你为什么它被禁止并且这样的代码不能编译。最大的问题是执行这样明确的代码,所以语言规范说不允许这样的结构。
      【解决方案4】:

      因为在这样的情况下无法解决应该调用哪个重载方法:

      public static void main(String... args) {
          method1("aaa");
      }
      

      【讨论】:

        【解决方案5】:

        在设计重载解析等内容时需要考虑几点。

        省略返回类型重载的原因:

        1. 简化忽略函数返回值(就像人们经常对错误代码所做的那样)。
        2. 使程序更易于人类读者理解。特别是,这就是在 Python 中它们根本没有函数重载的原因。 (口味问题)
        3. C 传统。当语言来自 C 家族并且设计人员不认为有什么大不了的时候,它就会像往常一样......

        在返回类型上添加重载的原因:

        1. 很难忽略返回值。这可能很方便并且可以节省一些打字时间,但总有一天会咬你一口。
        2. 表现力(当然与易于消化相反:))。你有没有想过写像int x = json.get("int_value"); float y = json.get("float_value");这样的东西?在某些语言(如 C++)中,这仍然可以通过代理和强制转换运算符实现,但返回类型的重载会容易得多。
        3. 表现力。每次您将 retun 值作为对函数的引用只是为了重用其资源时,这可能是返回类型的重载(带有隐藏参数)。考虑string s; getline(cin, s);string s = getline(cin);。这就是表现力与引用透明度以及最终易于代码消化相结合的地方。

        现在回到你的问题“为什么?”。既然您问的是 Java,答案显然是因为 James 重视忽略返回类型重载的原因,而不是将它们包含在语言中的原因。

        【讨论】:

          【解决方案6】:

          我自己曾经有过同样的问题,虽然我可以看到当您不将返回值分配给适当类型的变量时编译器如何不知道要调用哪个函数,但为什么要抛出功能层面的错误?为什么不在调用函数的时候呢?基本上,一旦您承诺签名仅在返回值上有所不同,您就可以确保以这种方式使用它们,然后,只有这样,编译器才会抱怨。当然,要让它与严格的一次性编译器一起工作可能需要一些额外的工作,但我认为它可以运行。

          【讨论】:

            【解决方案7】:

            您可以将函数调用为过程:method1("arg"); 其中 method1 是列表中的第二个方法 (String method1(String arg){})。然后编译器将无法将其与第一个 (void method1(String arg){}) 区分开来。

            【讨论】:

              【解决方案8】:

              编译器负责方法绑定。当它遇到 methodName() 时,它必须绑定到某个方法定义,此时它可能不知道方法的返回类型。因此方法返回类型不包含在方法签名中。编译器根据方法签名绑定方法。

              【讨论】:

                【解决方案9】:

                当编译器遇到方法调用时。它将方法调用静态绑定到定义的方法之一。 让我们看看如果返回类型包含在方法签名中会发生什么

                class Example{
                    public void method1(String arg){ return arg} 
                    public String method1(String arg){}
                    public static void main(String[] args){
                        Example e = new Example();
                        e.method1("abc");   
                     }  
                } 
                

                e.method1("abc") 如果方法签名中包含返回类型,编译器将不知道要绑定到哪个方法。

                【讨论】:

                  【解决方案10】:

                  方法重载是根据参数的数量和类型而不是返回类型来检查的。这就是您收到错误消息的原因。

                  【讨论】:

                  • 因为它试图定义两个具有相同签名的方法。正在方法表中检查并且不允许。
                  • 因为当编译器在一个类中找到两个具有相同签名的方法定义时,它无法区分哪一个被保存在方法表中并产生错误。我想你很清楚这是不可能的在公共范围内声明两个具有相同名称的字段..
                  猜你喜欢
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-04-13
                  • 2018-01-02
                  • 2021-04-04
                  • 2013-04-15
                  • 2014-10-24
                  • 2014-08-18
                  • 1970-01-01
                  相关资源
                  最近更新 更多