【发布时间】:2021-07-05 12:22:59
【问题描述】:
为什么方法的返回类型不包含在签名中?
一个例子
public void method1(String arg){...}
public String method1(String arg){...}
这会导致错误。
【问题讨论】:
标签: java
为什么方法的返回类型不包含在签名中?
一个例子
public void method1(String arg){...}
public String method1(String arg){...}
这会导致错误。
【问题讨论】:
标签: java
这样做是因为编译器无法找出所有上下文中的重载。
例如,如果您调用
String x = method1("aaa");
编译器知道您正在寻找第二个重载。但是,如果您调用
method1("aaa");
像这样,编译器不知道你想调用这两个方法中的哪一个,因为调用返回String的方法并丢弃结果是可以的。为避免此类歧义,Java 禁止仅在返回类型上有所不同的重载。
【讨论】:
由于您的问题在标题中没有涉及任何特定的编程语言(我知道它在标签中涉及),所以我将分享我最近使用 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)
【讨论】:
你不能只在它的返回类型上重载一个方法。这简直是非法的。让我们暂时假设使用返回类型重载方法是合法的,并且您定义了两个method1 方法。现在我们要调用返回String object:
String string = method1(sth);
JVM理论上可以识别你想要调用的方法,但是这样的调用呢:
method1(sth);
正如您所见,这两种方法都可以被调用,并且这样的操作是明确的。 JVM 不知道它应该调用哪个方法。这就是禁止这种重载的原因。
【讨论】:
因为在这样的情况下无法解决应该调用哪个重载方法:
public static void main(String... args) {
method1("aaa");
}
【讨论】:
在设计重载解析等内容时需要考虑几点。
省略返回类型重载的原因:
在返回类型上添加重载的原因:
int x = json.get("int_value"); float y = json.get("float_value");这样的东西?在某些语言(如 C++)中,这仍然可以通过代理和强制转换运算符实现,但返回类型的重载会容易得多。string s; getline(cin, s); 与string s = getline(cin);。这就是表现力与引用透明度以及最终易于代码消化相结合的地方。现在回到你的问题“为什么?”。既然您问的是 Java,答案显然是因为 James 重视忽略返回类型重载的原因,而不是将它们包含在语言中的原因。
【讨论】:
我自己曾经有过同样的问题,虽然我可以看到当您不将返回值分配给适当类型的变量时编译器如何不知道要调用哪个函数,但为什么要抛出功能层面的错误?为什么不在调用函数的时候呢?基本上,一旦您承诺签名仅在返回值上有所不同,您就可以确保以这种方式使用它们,然后,只有这样,编译器才会抱怨。当然,要让它与严格的一次性编译器一起工作可能需要一些额外的工作,但我认为它可以运行。
【讨论】:
您可以将函数调用为过程:method1("arg"); 其中 method1 是列表中的第二个方法 (String method1(String arg){})。然后编译器将无法将其与第一个 (void method1(String arg){}) 区分开来。
【讨论】:
编译器负责方法绑定。当它遇到 methodName() 时,它必须绑定到某个方法定义,此时它可能不知道方法的返回类型。因此方法返回类型不包含在方法签名中。编译器根据方法签名绑定方法。
【讨论】:
当编译器遇到方法调用时。它将方法调用静态绑定到定义的方法之一。 让我们看看如果返回类型包含在方法签名中会发生什么
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") 如果方法签名中包含返回类型,编译器将不知道要绑定到哪个方法。
【讨论】:
方法重载是根据参数的数量和类型而不是返回类型来检查的。这就是您收到错误消息的原因。
【讨论】: