【问题标题】:Theoretical inquiry about overloading and type promotion in javajava中重载和类型提升的理论探究
【发布时间】:2018-06-19 02:58:44
【问题描述】:

如果有add(int,long)add(long,int)这样的两个方法,这样的调用add(10,10)会被认为是歧义的。

但是如果我们有这样的例子,为什么它仍然被认为是模棱两可的??

static void add(short num1, short num2) {
    System.out.println("add(short, short)");
}

static void add(byte num1, long num2) {
    System.out.println("add(byte, long)");
}

public static void main(String[] args) {
    byte num1 = 10;
    byte num2 = 10;

    add(num1, num2);
}

我想知道编译器是如何确定它是歧义的?虽然(在我看来)不应该因为add(short, short) 需要两步类型提升,而add(byte, long) 需要三步类型提升.. 还是我有误解??

【问题讨论】:

  • 为什么你认为它不是模棱两可?
  • 我在问为什么会模棱两可?你能证明这一点吗?
  • 应该调用哪个?为什么?
  • bytes 可以是shorts
  • 所以你不知道它应该调用哪一个,但你希望编译器知道?

标签: java overloading type-promotion


【解决方案1】:

请参阅 8.4.9. Overloading - from the Java Language Specification"overloading resolution procedure" - 特别是 15.12.2.5。选择最具体的方法

如果多个成员方法既可访问又适用于方法调用,则有必要选择一个为运行时方法分派提供描述符。 Java 编程语言使用选择最具体方法的规则。

..

一种适用的方法 m1 比另一种适用的方法 m2更具体,对于使用参数表达式 e1、...、ek、if 的调用,以下任何一种是真的:

  • [..]

  • m2 不是泛型的,m1 和 m2 可以通过严格或松散的调用来应用,其中 m1 具有形参类型 S1,...,Sn,m2 具有形参类型 T1,...,Tn,对于所有 i (1 ≤ i ≤ n, n = k),参数 ei 的类型 Si 比 Ti 更具体

  • [..]

..

可能没有一种方法是最具体的,因为有两种或多种方法是最具体的.. [具体/抽象有更多规则..]

否则方法调用不明确,出现编译时错误。

Java 编译器只是遵循这些规则;不同的语言将遵循不同的规则,在决定选择哪个重载时,人类可能会发明自己的非 Java 规则..


对于要选择为更具体的方法,它必须对所有参数更具体。因此,当以add(byte,byte) 调用时,示例案例会导致不明确的调用,因为:

  • add(short num1 /* less specific */, short num2 /* MORE specific */)
  • add(byte num1 /* MORE specific */, long num2 /* less specific */)

但是,如果将add(byte num1, long num2) 更改为add(byte num1, short num2),它将编译,因为:

  • add(short num1 /* less specific */, short num2 /* as specific */)
  • add(byte num1 /* MORE specific */, short num2 /* as specific */)

原语的关系在4.10.1. Subtyping among Primitive Types:long > int > short > byte:

【讨论】:

  • 天哪,那套规则太复杂了,所以我用“..这里有很多规则..”这并不能令人满意地显示 Java 编译器所采用的确切过程..跨度>
  • 小崽子,这是我提炼相关规则和选择过程的机会。 YMMV 和 tldr;这就是 Java 的工作方式。
  • 你成功了兄弟 :)
【解决方案2】:

将实际参数类型与方法参数列表匹配在两种情况下都需要类型强制,因此两者都不是“完美”匹配,因此是模棱两可的。如果你添加

static void add(byte num1, byte num2) {
    System.out.println("add(byte, byte)");
}

这是一个完美的匹配,没有歧义。

【讨论】:

  • 我不认为这是因为这两个参数都需要类型提升,因为如果我们有这些方法而不是上面提到的add(int,int)add(long,long) 就不会有歧义
猜你喜欢
  • 1970-01-01
  • 2019-10-22
  • 1970-01-01
  • 2011-12-28
  • 2015-03-30
  • 2023-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多