Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.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_Overloading - Fatal编程技术网

Java重载规则

Java重载规则,java,overloading,Java,Overloading,我最近遇到了两个重载问题,我找不到答案,也没有java环境来运行一些测试代码。我希望有人能帮我整理一个java编译器重载时遵循的所有规则的列表,或者将我指向一个已经存在的列表 首先,当两个方法仅因最后一个varargs参数不同时,在什么情况下会调用每个方法,并且可以在没有任何args的情况下调用varargs方法 private void f(int a) { /* ... */ } private void f(int a, int... b) { /* ... */ } f(12); //

我最近遇到了两个重载问题,我找不到答案,也没有java环境来运行一些测试代码。我希望有人能帮我整理一个java编译器重载时遵循的所有规则的列表,或者将我指向一个已经存在的列表

首先,当两个方法仅因最后一个varargs参数不同时,在什么情况下会调用每个方法,并且可以在没有任何args的情况下调用varargs方法

private void f(int a) { /* ... */ }
private void f(int a, int... b) { /* ... */ }

f(12); // calls the former? I would expect it to
f(12, (int[])null); // calls latter, but passes null for b? 
  // Can I force the compiler to call the second method in the same fashion
  // as would happen if the first method didn't exist?
第二个问题,当两个方法因相互继承的类型不同而被调用时?我希望调用最派生的版本,并允许casting调用另一个

interface A {}
class B implements A {}
class C implements A {}

private void f(A a) {}
private void f(B b) {}

f(new C()); // calls the first method
f(new B()); // calls the second method?
f((A)(new B()); // calls the first method using a B object?

这是两个示例,但作为一名代码读取器,我更喜欢用于解决此问题的精确有序规则的规范列表,因为我经常没有时间设置生成环境来检查编译器正在做什么。

重载与重写

正如您所指出的,选择正确的方法实现是在运行时完成的,现在要调用的方法的签名是在编译时决定的

在编译时重载方法选择

第15.12节中的(JLS)详细解释了编译器选择正确调用方法所遵循的过程

在这里,您会注意到这是一个编译时任务。JLS在第15.12.2小节中规定:

此步骤使用方法的名称参数表达式的类型 找到既可访问又适用的方法 这种方法可能不止一种,在这种情况下,选择最具体的一种

通常,如果varargs方法与其他候选方法竞争,则最后选择varargs方法,因为它们被认为不如接收相同参数类型的方法具体

要验证其编译时性质,可以执行以下测试

像这样声明一个类并编译它(即
javac ChooseMethod.java

声明调用第一个类的方法的第二个类并对其进行编译(即
javacmethodchooser.java

如果运行该程序(即
java方法选择器
),则输出为
Number

现在,向
ChooseMethod
类添加第二个更具体的重载方法,并重新编译它(但不要重新编译另一个类)

如果再次运行main,输出仍然是
Number

基本上,因为它是在编译时决定的。如果重新编译
MethodChooser
类(带有main的类),并再次运行该程序,则输出将是
Integer

同样地,若要强制选择其中一个重载方法,则参数的类型必须在编译时与参数的类型相对应,而不仅仅是在运行时

在运行时覆盖方法选择

同样,方法的签名在编译时决定,但实际实现在运行时决定

像这样声明一个类并编译它

public class ChooseMethodA {
   public void doSomething(Number n){
    System.out.println("Number A");
   }
}
然后声明第二个扩展类并编译:

public class ChooseMethodB extends ChooseMethodA {  }
在MethodChooser类中,您可以执行以下操作:

public class MethodChooser {
    public static void main(String[] args) {
        ChooseMethodA m = new ChooseMethodB();
        m.doSomething(10);
    }
}
如果您运行它,您将获得输出
编号A
,这是正常的,因为该方法未在
ChooseMethodB
中被重写,因此调用的实现是
ChooseMethodA
的实现

现在,在
methodchooseb
中添加一个重写的方法:

public void doSomething(Number n){
    System.out.println("Number B");
}
然后重新编译这个,然后再次运行main方法

现在,您将获得输出
编号B

因此,实现是在运行时选择的,不需要重新编译
MethodChooser

第一个问题:

你的假设是正确的。对
f()
的第二次调用将调用varargs方法。您可以使用以下命令让编译器调用第二个方法:

private void f(int a) {
    f(a, null);
}
第二个问题:


对。但是,不能扩展接口。如果你把
A
改成一个抽象类,事情就会被编译。

我想回答的问题是,什么决定了“最具体”。是否有一个编号列表可以用来确定将调用哪个函数。@Peter您是否阅读了我从JLS共享的链接?“如果你在那里找不到答案,你在别处也找不到。”我在发表评论后这样做了。这是编译器应该做什么的最终参考,这才是我真正想要的链接。这肯定不是最容易阅读的,我可能会尝试对它进行更实际的提炼,因为其他东西似乎不存在。@PeterOehlert由于解释中使用的正式语言,这肯定需要一些时间来消化。当然,如果您坐下来,耐心地尝试几行代码,过段时间您可能会想出一个值得分享的示例概要。我想我很想看到它们,它们值得在任何博客或这里发表,作为你自己问题的答案。第二个粗体标题应该是编译时重载方法选择。你可以尝试
f(a,new int[0])
public class MethodChooser {
    public static void main(String[] args) {
        ChooseMethodA m = new ChooseMethodB();
        m.doSomething(10);
    }
}
public void doSomething(Number n){
    System.out.println("Number B");
}
private void f(int a) {
    f(a, null);
}