25

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

一个例子

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

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

它会导致错误。

4

10 回答 10

42

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

例如,如果您调用

String x = method1("aaa");

编译器知道您正在寻找第二个重载。但是,如果你打电话

method1("aaa");

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

于 2012-11-09T19:05:53.920 回答
8

由于您的问题没有针对标题中的任何特定编程语言(我知道它在标签中),我将分享我最近使用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)
于 2015-01-22T00:30:27.280 回答
3

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

String string = method1(sth);

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

method1(sth);

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

于 2012-11-09T19:05:21.843 回答
2

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

public static void main(String... args) {
    method1("aaa");
}
于 2012-11-09T19:10:51.447 回答
1

在设计诸如重载决议之类的东西时,有几点需要考虑。

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

  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);vs string s = getline(cin);。这就是表达性与引用透明性以及最终易于代码消化的结合。

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

于 2017-03-13T11:53:16.203 回答
1

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

于 2020-02-22T04:47:30.830 回答
0

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

于 2012-11-09T19:10:07.347 回答
0

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

于 2019-10-11T13:28:09.687 回答
0

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

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") 如果方法签名中包含返回类型,编译器将不知道要绑定到哪个方法。

于 2021-07-05T04:22:59.530 回答
-1

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

于 2012-11-09T19:14:51.340 回答