【问题标题】:How does Java distinguish these multiple methods with the same name/signature?Java 如何区分这些具有相同名称/签名的多个方法?
【发布时间】:2013-08-21 14:33:44
【问题描述】:

我今天正在寻找一个错误,我发现我们的一个班级中有一些奇怪的事情。我剪掉了尽可能多的代码在这里发布:

class A {
    static int obtainNumber() { return 42; }
    static int obtainNumber() { return 3; }
    static int obtainNumber() { return -1; }
    static {
        System.out.println(obtainNumber());
    }
}

这个类有 3 个名称和签名完全相同的方法。起初我认为这是无效代码,但后来 eclipse 会以红色突出显示代码。它确实有效:

javac A.java && java A
42
Exception in thread "main" java.lang.NoSuchMethodError: main

所以我想也许 Java 会使用它看到的第一个。我重新订购测试:

class A {
    static int obtainNumber() { return 3; }
    static int obtainNumber() { return -1; }
    static int obtainNumber() { return 42; }
    static {
        System.out.println(obtainNumber());
    }
}

不,同样的结果:

javac A.java && java A
42
Exception in thread "main" java.lang.NoSuchMethodError: main

我想也许它使用 42 的那个,因为它是最大的。为了测试这一点,我取了原始值并更改了返回值:

class A {
    static int obtainNumber() { return 0; }
    static int obtainNumber() { return 1; }
    static int obtainNumber() { return 2; }
    static {
        System.out.println(obtainNumber());
    }
}

还是知道用第一个:

javac A.java && java A
0
Exception in thread "main" java.lang.NoSuchMethodError: main

如果我重新排序:

class A {
    static int obtainNumber() { return 1; }
    static int obtainNumber() { return 0; }
    static int obtainNumber() { return 2; }
    static {
        System.out.println(obtainNumber());
    }
}

同样的结果:

javac A.java && java A
0
Exception in thread "main" java.lang.NoSuchMethodError: main

我认为 Java 是一种基于文本的语言,我认为这使得这种事情变得不可能。 Java如何跟踪哪个方法是哪个?

【问题讨论】:

  • 如果您注意到,所采用的是与其他语法不同的语法。也许这可能会根据隐藏的字符或语法怪癖为您提供线索。
  • 为什么有人会这样做?这就像在程序员身上玩的魔术
  • 来自蝙蝠侠黑暗骑士的@Jim:有些人只想看着世界燃烧
  • 正因为如此,我才产生了这么多坏主意
  • 您应该检查项目是否存在编码问题,特别是如果它已从其他系统类型或可能有故障的旧存储介质中恢复,或已暴露于携带瘟疫的旧设备。

标签: java unicode polymorphism


【解决方案1】:

我刚刚将它复制/粘贴到我的 IDE 中,虽然这是一个奇迹,但在尝试保存文件时出现了一条错误消息,清除了这个问题

保存无法完成。如果问题仍然存在,请尝试文件 > 另存为...。

原因: 某些字符无法使用“Cp1252”字符编码进行映射。 更改编码或删除“Cp1252”字符编码不支持的字符。

所以,这些方法没有相同的名称,只是使用看起来相同的字符。

更多关于 Java 源文件字符编码的信息:

【讨论】:

    【解决方案2】:

    隐藏字符。源码相当于

    static int obtainNumber() { return 42; }

    static int obtain<b>\ufeff</b>Number() { return 3; }

    static int obtain<b>\ufeff\ufeff</b>Number() { return -1; }

    为避免此类问题,我的源文件严格使用 US-ASCII。我想确定我看到的字符正是编译器看到的字符。

    【讨论】:

      【解决方案3】:

      我的原创评论:

      如果您注意到,所采用的是与其他语法不同的语法。也许这可能会根据隐藏的字符或语法怪癖为您提供线索。

      我将它粘贴到 Eclipse 中,并注意到一个额外的字符。我将保存的文件(在 CP1252 中)放入十六进制编辑器,并找到了一个字节顺序标记。

      当我查看时,CP1252 没有字节顺序标记,但字符本身在 CP1252 中。可能输入了杂散的 Unicode 字符。

      当我仔细观察时,另一种方法在另一个字节顺序中有另一个字节顺序标记。

      他们是怎么来的,我们永远不会知道。但是,我们确实知道编译器会采用 没有 字节顺序标记的那个。

      您应该检查项目是否存在编码问题,特别是如果它已从其他系统类型或可能有故障或已暴露于旧设备的旧存储介质中恢复。

      我们现在确实需要通过元 sometime 来处理这种 FGITW 行为。

      【讨论】: