Ответ 1
Как парень, который написал механизм разрешения перегрузки для Nashorn, я всегда очарован угловыми случаями, с которыми сталкиваются люди. К лучшему или худшему, вот как это получается:
Решение метода перегрузки Nashorn позволяет максимально точно подбирать спецификацию языка Java (JLS), но также допускает преобразования JavaScript. JLS говорит, что при выборе метода для вызова перегруженного имени методы переменной arity могут рассматриваться для вызова только тогда, когда не применяется применимый метод фиксированной arity. Обычно при вызове с Java test(String)
не применимо к вызову с int
, поэтому метод test(Integer...)
будет вызван. Однако, поскольку JavaScript фактически допускает неявное преобразование числа в строку, он применим и рассматривается перед любыми методами переменной arity. Отсюда наблюдаемое поведение. Arity превосходит неконверсию. Если вы добавили метод test(int)
, он будет вызван перед методом String, поскольку он фиксирует arity и более специфичен, чем String.
Можно утверждать, что мы должны изменить алгоритм выбора метода. Многое было уделено этому, так как еще до проекта Nashorn (даже когда я разрабатывал Dynalink самостоятельно). Текущий код (как это реализовано в библиотеке Dynalink, над которой на самом деле основан Насборн) следует за JLS к письму, и в отсутствие конверсий по языковому типу будут выбирать те же методы, что и Java. Однако, как только вы начнете расслаблять свою систему типов, все начинает тонко меняться, и чем больше вы ее расслабляете, тем больше они будут меняться (и JavaScript релаксирует много), и любое изменение алгоритма выбора будет иметь некоторые другие Боюсь, странное поведение, с которым кто-то столкнется... он просто поставляется с системой расслабленного типа. Например:
- Если мы допустили, что varargs следует рассматривать вместе с fixargs, нам нужно будет выработать "более конкретную" связь между различными методами arity, что не существует в JLS и, следовательно, несовместимо с ним, и будет иногда вызывать varargs, если в противном случае JLS будет вызывать вызов fixargs.
- Если мы запретили JS-разрешенные преобразования (таким образом, чтобы
test(String)
не считалось применимым к параметруint
), некоторые разработчики JS чувствовали бы себя обремененными необходимостью прервать свою программу с вызовом метода String (например, t26 > для обеспеченияx
является строкой и т.д.
Как вы можете видеть, независимо от того, что мы делаем, что-то другое пострадает; перегруженный метод выбора находится в плотном месте между системами Java и JS и очень чувствителен к даже небольшим изменениям в логике.
Наконец, когда вы вручную выбираете среди перегрузок, вы также можете придерживаться неквалифицированных имен типов, если нет никакой двусмысленности в методах потенциальных методов для имени пакета в позиции аргумента, то есть
API["test(Integer[])"](1);
тоже должен работать, не нужно префикс java.lang.
. Это может немного облегчить синтаксический шум, если вы не можете переделать API.
НТН, Аттила.