Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/335.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_Virtual Functions_Dynamic Dispatch - Fatal编程技术网

Java 为什么方法重载解析是在编译时确定的?

Java 为什么方法重载解析是在编译时确定的?,java,virtual-functions,dynamic-dispatch,Java,Virtual Functions,Dynamic Dispatch,我试图理解为什么我们有多态性/动态绑定和重写的方法,而不是重载的方法。我知道间接的是,我们可以把索引放在一个VTABLE中,允许我们用C++语言或java语言来实现这一点。我很好奇为什么解决重载方法的情况不一样——我的直觉让我相信我们可以有一个间接级别,允许我们在运行时根据运行时类型确定调用哪个重载方法 我想知道这个设计决定是出于性能原因还是因为我忽略了额外的复杂性。 < P>我没有读过语言设计师的想法,所以不能真正告诉你。我是这样想的: 重写方法是同一方法在超类/子类层次结构的不同级别上的不

我试图理解为什么我们有多态性/动态绑定和重写的方法,而不是重载的方法。我知道间接的是,我们可以把索引放在一个VTABLE中,允许我们用C++语言或java语言来实现这一点。我很好奇为什么解决重载方法的情况不一样——我的直觉让我相信我们可以有一个间接级别,允许我们在运行时根据运行时类型确定调用哪个重载方法


我想知道这个设计决定是出于性能原因还是因为我忽略了额外的复杂性。

< P>我没有读过语言设计师的想法,所以不能真正告诉你。我是这样想的:

  • 重写方法是同一方法在超类/子类层次结构的不同级别上的不同实现。子类通常使用相同的方法签名(允许它返回更具体的类型并声明更少的要抛出的异常,但它不能完全重新定义方法头,否则它将不再是重写)
  • 重载方法实际上只是碰巧具有相同名称的不同方法。然后使用参数类型进行区分。就像编译器总是在编译时决定调用哪个方法一样,重载方法也是如此
作为一个观察(可能是一个次要的观察),对于重载方法的运行时解析,我们不能再静态地检查返回值。想象一下我们有

public boolean foo(Number n);
public String foo(Integer i);
现在,我发现这样调用前面的
foo()
是非常自然的:

    boolean result = foo(myNumber);
现在,如果
myNumber
恰好是一个
Integer
,则将调用后者
foo()
。它将返回一个
字符串
,并且在运行时发生类型转换错误。我不会感到惊讶

…那么,为什么我们仍然可以使用运行时多态性并将其考虑在内 静态类型,但如果我们对 重载方法


Java有两种类型:静态类型和运行时类型。当我将
整数
存储到声明为
数字
的变量中时,
数字
是静态类型,
整数
是运行时类型(顺便说一句,类型与类不同)。您是对的,当我执行
myObject.foo(arg)
时,
myObject
的运行时类型决定调用
foo()
的哪个实现。可以想象,
arg
的运行时类型也可能参与决策。它会变得更复杂,我不确定它的好处。

重载方法是具有相同名称但采用不同参数的方法。您只需查看作为名称一部分的参数的类型和顺序(以及它返回的值的类型)

在C++中,这实际上是更“暴露”的——这个语言在内部修改名称以匹配参数,<代码>空隙h(int,char)< /> >变成类似<代码> HyfFiC/<代码>和<代码>虚空H(int)< /代码>,如<代码> HyfFiF。这些损坏的名称偶尔会出现在一些地方,比如关于它们未被解析的错误消息。在Java中,这是较少公开的,但在内部具有可比性。这也被称为“签名”


然后,您可以将问题简化为“如果方法具有不同的名称,为什么它们在编译时解析,而不是在运行时解析?”。具有不同签名的两种方法之间的分辨率不能随时间而改变,因此没有理由也没有好处延迟它。

因为以这种方式设计它符合Java的设计原则,即Java的类型系统是静态的。要获得更详细的答案,您必须询问语言设计者。@Sweeper我想我可能从根本上搞不清楚为什么我们仍然可以使用运行时多态性,并将其视为静态类型,但如果我们对重载方法进行动态解析,就不会这样了。也许这就是我想要的答案。基于运行时类型的重载解析有用吗?我想这只会让我对代码的行为感到困惑。不过,我理解你的问题。有些编程语言中,正常的方法参数会影响运行时的方法解析,就像接收方参数(“this”参数)一样。这种机制通常被称为。许多动态语言都有这个特性,例如Clojure和Groovy。这些语言的支持者经常坚持认为该功能是一个非常有用的设计工具。谢谢!您提到的关于返回值的静态类型检查非常有意义。我想在收益方面,当谈到访问者模式时,人们提到的一个共同点是,它是一个支持双重分派的解决方案,因此我想我的问题是,为什么当时它没有直接构建到语言中。我很感谢你的回答——也许我的问题可以更清楚一些。这个问题更多的是关于语言设计的,而简化的问题并不是我想要的。名称损坏虽然很重要,但并不能确切地回答为什么重载方法解析不能在运行时使用间接层进行解析。我要问的更多的问题是,为什么我们首先需要类似访问者模式的东西,或者为什么我们不能在语言中直接支持多个分派。一切都可以在运行时完成,而解释语言正是这样做的。