Перегрузка Math.sqrt: перегрузочный метод, кажется, скрывает оригинальный - PullRequest
9 голосов
/ 17 февраля 2010

пытается перегрузить статический метод java.lang.Math.sqrt для int типа:

import static java.lang.Math.sqrt;

class Test
{
    private static double sqrt(int n)
    {
        return sqrt(1.0 * n);
    }

    public static void main(String[] args)
    {
        System.out.println(sqrt(1));
    }
}

возникает странная ошибка:

Test.java:7: sqrt(int) in Test cannot be applied to (double)
                return sqrt(1.0 * n);
                       ^
1 error

Но при явной ссылке на метод java.lang.Math.sqrt все идет хорошо:

class Test
{
    private static double sqrt(int n)
    {
        return Math.sqrt(1.0 * n);
    }

    public static void main(String[] args)
    {
        System.out.println(sqrt(1));
    }
}

Используется стандартный компилятор javac , версия 1.6.0_16 .

Итак, вопросы:

  1. Почему компилятор не может разрешить перегрузку в первом случае?
  2. Где это поведение указано в спецификациях языка Java?

Заранее спасибо.

Ответы [ 5 ]

13 голосов
/ 17 февраля 2010

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

Относительно того, где указано это поведение: Спецификация языка определяет перегрузку следующим образом :

Если два метода класса (оба они объявлены в одном и том же классе или оба унаследованы классом, или один объявлен и один унаследован) имеют одно и то же имя, но подписи не эквивалентны переопределению, тогда имя метода сказал, что перегружен.

Обратите внимание, что в нем написано "два метода класса". Поэтому методы, импортированные из другого класса, просто не рассматриваются.

Так как ваше определение не является перегрузкой Math.sqrt, оно затеняет его согласно разделу 6.3.1 определения :

Объявление d метода с именем n затеняет объявления любых других методов с именем n, которые находятся во вложенной области действия в точке, где d встречается во всей области действия d.

3 голосов
/ 17 февраля 2010

Это вполне нормально. Написав этот код, вы никоим образом не перегружали метод Math.sqrt, вы просто определили Test.sqrt(int) в качестве аргумента.

Тогда возникает вопрос о вашем сообщении об ошибке.

При определении метода Test.sqrt вы перегружаете (в этом классе) статический импорт, который вы сделали.

Итак, при вызове sqrt (1.0 * n) компилятор считает, что вы пытаетесь вызвать Test.sqrt (int) с двойным, что, очевидно, невозможно.

2 голосов
/ 17 февраля 2010

Вы на самом деле не перегружены.Вещи зависают из-за двусмысленности;компилятор видит return sqrt(1.0 * n);, он предполагает, что вы говорите о функции sqrt(int) в классе Test, а не в lang.Math.Это предпочтительное поведение;в конце концов, вы, вероятно, не хотите указывать class.method каждый раз, когда пытаетесь вызвать функцию-член.И компилятор не разрешает это потому, что в вашей конкретной ситуации он предполагает, что вы допустили ошибку, и не понимает, что вы намеревались вызвать sqrt in lang.Math.

1 голос
/ 17 февраля 2010

Да, sqrt(int) in Test cannot be applied to (double)

Переименуйте вашу функцию под другим именем, если вы хотите вызвать Math.sqrt:

private static double mysqrt(int n)
{
    return sqrt(1.0 * n);
}
0 голосов
/ 17 февраля 2010

В первом вызове упоминается тот метод, который вы возвращаете, ожидая, что int будет его параметром, но вы отправляете ему double. так что это дает ошибку компилятора.

Но при втором вызове вы обращаетесь к Math.sqrt (), который работает нормально.

...