【问题标题】:overloading with both widening and boxing加宽和装箱超载
【发布时间】:2011-02-07 12:59:47
【问题描述】:
public void add(long... x){}
public void add(Integer... x){}

add(2);

这会产生错误...为什么不使用加宽和装箱来执行重载?

但是没有可变参数的重载工作正常

public void add(long x){}
    public void add(Integer x){}

    add(2);

此处将执行 add(long x) 以扩大节拍...为什么不使用相同的概念 变量参数

【问题讨论】:

  • 对我来说很好。你看到哪个错误?你的java版本是多少?您是否有可能使用 5 之前的 java?
  • 我正在使用 java 6 ..boxig 仅来自 java 5..widening 来自 java 5..so 在装箱和 var arg 之前选择加宽以不违反现有代码(在 java 5 之前) )
  • 显然是模棱两可的@AlexR

标签: java overloading


【解决方案1】:

Java 编译器执行 3 次尝试来选择合适的方法重载 (JLS §15.12.2.1):

  • 第 1 阶段:确定子类型适用的匹配 Arity 方法
    (可能的装箱转换和带有可变参数的方法被忽略)

  • 第 2 阶段:确定方法适用的匹配 Arity 方法 调用转换
    (考虑装箱转换,但忽略带有可变参数的方法)

  • 第 3 阶段:确定适用的可变 Arity 方法
    (检查所有可能性)

因此,使用您的示例,它的工作原理如下:

  • 不带可变参数:add(long x) 被标识为第一阶段唯一适用的方法(此方法通过子类型适用,因为intlong§JLS 4.10.1 的子类型),因此以下阶段不执行。

  • 使用可变参数:重载解析算法进入阶段 3,这两种方法都被识别为适用,编译器无法选择其中最具体的方法(选择最具体的方法是另一种复杂的算法),因此它会报告歧义。

另请参阅:

【讨论】:

    【解决方案2】:

    因为它是模棱两可的

    2 可以是Integerlong,并且可以同时解析两者。你让编译器混淆了调用谁:)


    5.12.2.2 选择最具体的方法

    如果有多个方法声明 既可访问又适用于 方法调用,需要 选择一个来提供描述符 用于运行时方法分派。这 Java 编程语言使用 规则,最具体的方法是 选择。非正式的直觉是 一种方法声明更多 如果有的话,比另一个更具体 第一种方法处理的调用 可以传给另一个 没有编译时类型错误。

    具体定义如下。 让 m 是一个名字并假设有 是两个命名方法的声明 m,每个都有 n 个参数。认为 一个声明出现在一个 类或接口 T 并且 参数类型为 T1, . . . , Tn;此外,假设另一个 声明出现在一个类中或 接口 U 和类型 参数为 U1, 。 . . ,联合国。然后 在 T 中声明的方法 m 更 比在中声明的方法 m 更具体 U 当且仅当同时满足以下两个条件 是真的:

    T可以通过方法转换为U 调用转换。 Tj 可以是 通过方法调用转换为 Uj 转换,对于从 1 到 n 的所有 j。一种 方法被称为最大 特定于方法调用,如果它 适用且可访问并且存在 没有其他适用和可访问的 更具体的方法。如果有 正是一个最具体的 方法,那么它其实是最 具体方法;这是必然的 比任何其他方法更具体 这是适用和可访问的。它 然后受到一些进一步的 编译时检查,如中所述 §15.12.3.

    可能没有方法是 最具体的,因为有两个 或更具体的方法。在 本例:

    如果所有最大特定的方法 具有相同的签名,则:如果一个 最具体的方法是 没有声明抽象,它是最 具体方法。否则,所有 最具体的方法是 必须声明为抽象的。这 选择最具体的方法 在最大的任意之间 具体方法。然而,最 具体方法考虑抛出 一个检查的异常当且仅当 该异常在 throws 的每个子句 最具体的方法。否则, 我们说方法调用是 模棱两可,编译时错误 发生。

    15.12.2.3 示例:重载歧义

    Consider the example:
    class Point { int x, y; }
    class ColoredPoint extends Point { int color; }
    
    class Test {
        static void test(ColoredPoint p, Point q) {
            System.out.println("(ColoredPoint, Point)");
        }
        static void test(Point p, ColoredPoint q) {
            System.out.println("(Point, ColoredPoint)");
        }
        public static void main(String[] args) {
            ColoredPoint cp = new ColoredPoint();
            test(cp, cp);                                           // compile-time error
        }
    }
    

    此示例在编译时产生错误。问题是有两个适用和可访问的测试声明,并且没有一个比另一个更具体。因此,方法调用是模棱两可的。 如果添加了第三种测试定义:

    static void test(ColoredPoint p, ColoredPoint q) {
        System.out.println("(ColoredPoint, ColoredPoint)");
    }
    

    那么它会比其他两个更具体,方法调用将不再模棱两可。

    【讨论】:

    • 具体来说,一种方法并不比另一种更具体。 (System.out.println(new char[] { 'x' }); 按预期工作,与PrintStream.println(Object) 无关。)方法重载 - 如果合理,请避免这样做。
    • Jigar,我的大部分回答都很好,但我认为在这种情况下你错了。 Java 非常清楚区分 long 和 int。常数 5 是 int,5L 是 long。所以这两种方法是没有歧义的。我尝试了他的代码,它编译并运行良好。奇怪的是它总是调用长版本。当我将 Integer 更改为 int 时,它开始“正确”地运行。
    • @Alex 谢谢 :) 。我什至尝试了相同的代码,但它无法为我编译,检查this
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-01-23
    • 1970-01-01
    • 2012-01-31
    • 1970-01-01
    • 2014-05-26
    • 2013-09-03
    • 2011-02-28
    相关资源
    最近更新 更多