Java重载规则 [英] Java overloading rules

查看:107
本文介绍了Java重载规则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近遇到两个重载问题,我找不到答案,也没有java环境来运行一些测试代码。我希望有人可以通过汇编java编译器遵循的所有规则列表来帮助我重载或者交替指向我已经存在的列表。

I came across two overloading questions recently that I can't find an answer for and don't have a java environment to run some test code. I'm hoping someone can help me by assembling a list of all the rules that java compilers follow follow for overloading or alternately pointing me at a list that already exists.

首先,当两个方法只有最终的varargs参数不同时,在什么情况下每个方法都被调用,你可以调用没有任何args的varargs方法吗?

First, when two methods differ only by a final varargs parameter, under what circumstances do each get called and can you call the varargs method without any args?

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?

第二个问题,当两个方法因为彼此继承而被调用的类型不同时?我希望调用最派生的版本,并允许调用另一个版本。

Second question, when two methods differ by types inherited from one another which gets called? I'd expect the most derived version to be called, and casting allowed to call the other.

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?

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

These are the two examples, but as a code-reader I'd prefer a canonical list of the exact ordered rules used for resolving this as I frequently don't have time to setup a build environment to check what the compiler is doing.

推荐答案

重载与覆盖

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

The selection of the right implementation of method is done at runtime as you well pointed out, now the signature of the method to be invoked is decided at compile time.

在编译时重载方法选择

Java语言规范(JLS),第15.12节方法调用表达式解释详细介绍了编译器选择正确调用方法的过程。

The Java Language Specification (JLS) in section 15.12 Method Invocation Expressions explains in detail the process that the compiler follows to choose the right method to invoke.

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

There, you will notice that this is a compile-time task. The JLS says in subsection 15.12.2:


此步骤使用方法的名称用于查找可访问和适用的方法的参数表达式的类型

可能有多个此类方法,在这种情况下,选择最具体的方法。

This step uses the name of the method and the types of the argument expressions to locate methods that are both accessible and applicable There may be more than one such method, in which case the most specific one is chosen.

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

Typically, varargs methods are the last chosen, if they compete with other candidate methods, because they are considered less specific than the ones receiving the same parameter type.

要验证此编译时的性质,您可以进行以下测试。

To verify the compile-time nature of this, you can do the following test.

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

Declare a class like this and compile it.

public class ChooseMethod {
   public void doSomething(Number n){
    System.out.println("Number");
   }
}

声明第二个类调用第一个方法一个并编译它。

Declare a second class that invokes a method of the first one and compile it.

public class MethodChooser {
   public static void main(String[] args) {
    ChooseMethod m = new ChooseMethod();
    m.doSomething(10);
   }
}

如果你调用main,输出显示数字

If you invoke the main, the output says Number.

现在,向<$ c $添加第二个更具体的重载方法c> ChooseMethod class,并重新编译它(但不要重新编译其他类)。

Now, add a second more specific overloaded method to the ChooseMethod class, and recompile it (but do not recompile the other class).

public void doSomething(Integer i) {
 System.out.println("Integer");
}

如果再次运行main,输出仍为数字

If you run the main again, the output is still Number.

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

Basically, because it was decided at compile time. If you recompile the MethodChooser class (the one with the main), and run the program again, the output will be Integer.

因此,如果要强制选择其中一个重载方法,参数类型必须与编译时参数的类型相对应,而不仅仅是在运行时。

As such, if you want to force the selection of one of the overloaded methods, the type of the arguments must correspond with the type of the parameters at compile time, and not only at run time.

在运行时覆盖方法选择

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

Again, the signature of the method is decided at compile time, but the actual implementation is decided at runtime.

声明一个这样的类并编译它。

Declare a class like this and compile it.

public class ChooseMethodA {
   public void doSomething(Number n){
    System.out.println("Number A");
   }
}

然后声明第二个扩展类并编译:

Then declare a second extending class and compile:

public class ChooseMethodB extends ChooseMethodA {  }

在MethodChooser类中你可以:

And in the MethodChooser class you do:

public class MethodChooser {
    public static void main(String[] args) {
        ChooseMethodA m = new ChooseMethodB();
        m.doSomething(10);
    }
}

如果你运行它,你得到输出 Number A ,这没关系,因为该方法尚未在 ChooseMethodB 中被覆盖,因此被调用的实现是 ChooseMethodA

And if you run it you get the output Number A, and this is Ok, because the method has not been overriden in ChooseMethodB and therefore the implementation being invoked is that of ChooseMethodA.

现在,在 MethodChooserB :

public void doSomething(Number n){
    System.out.println("Number B");
}

重新编译这个,然后再次运行main方法。

And recompile just this one, and run the main method again.

现在,您获得输出数字B

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

As such, the implementation was chosen at runtime, and not recompilation of the MethodChooser class was required.

这篇关于Java重载规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆