Как Java различает эти несколько методов с тем же именем/сигнатурой?

Сегодня я отслеживал ошибку, и я заметил что-то странное в одном из наших классов. Я вырезал как можно больше кода, чтобы опубликовать здесь:

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

Этот класс имеет 3 метода с одинаковым именем и сигнатурой. Сначала я думал, что это неверный код, но затем затмение выделило бы код красным. Он работает:

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, какой метод является?

Ответ 1

Скрытые символы. Исходный код эквивалентен

static int obtainNumber() { return 42; }

static int obtain\ufeffNumber() { return 3; }

static int obtain\ufeff\ufeffNumber() { return -1; }

Чтобы избежать подобных проблем, мои исходные файлы - это строго US-ASCII. Я хочу быть уверенным, что символы, которые я вижу, точно компилятор символов видит.

Ответ 2

Я только что скопировал/вставил это в свою IDE, и хотя это было чудо, тогда при попытке сохранить файл появилось сообщение об ошибке:

Сохранить не удалось. Попробуйте Файл > Сохранить как... если проблема не устранена.

Причина: Некоторые символы не могут быть сопоставлены с использованием кодировки "Cp1252". Либо измените кодировку, либо удалите символы, которые не поддерживаются кодировкой "Cp1252".

Итак, эти методы не имеют одинакового имени, просто используйте символы, которые выглядят одинаково.

Дополнительная информация, связанная с кодировкой символов в исходных файлах Java:

Ответ 3

Мой оригинальный комментарий:

Если вы заметили, тот, который был взят, - это тот, у которого разный синтаксис, связанный с другими. Возможно, это может вас подсказать на основе скрытых символов или грамматических причуд.

Я вложил это в Eclipse и заметил немного лишнего персонажа. Я выбросил сохраненный файл (в CP1252) в шестнадцатеричный редактор и нашел отметку порядка байтов.

Когда я посмотрел, CP1252 не имеет знака порядка байтов, но символы сами находятся в CP1252. Возможно, появился паразитный символ юникода.

Когда я посмотрел более внимательно, другой метод имел еще один байтовый порядок в другом порядке байтов.

Как они пришли, мы никогда не узнаем. Однако мы знаем, что компилятор берет тот, у которого нет знака порядка байтов.

Вы должны проверить проект на предмет проблем с кодировкой, особенно если он был восстановлен из других системных типов или старых носителей данных, которые могут быть неисправными или подверглись воздействию устаревшего оборудования.

Нам действительно нужно иметь дело с этим поведением FGITW через meta sometime.