Статический импорт не работает, если у класса есть методы с тем же именем, что и у импортированных - PullRequest
6 голосов
/ 06 июля 2011

У меня есть Junit4 контрольный пример, который статически импортирует метод (ы) org.junit.Assert.assertEquals.

import static org.junit.Assert.assertEquals;

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

private void assertEquals(MyObj o1, MyObj o2)
{
    assertEquals(o1.getSomething(), o2.getSomething());
    assertEquals(o1.getSomethingElse(), o2.getSomethingElse());
    ...
}

Я ожидал, что код будет вести себя так, как будто я "перегружаю" импортируемые методы assertEquals, но похоже, что мой частный нестатический метод - скрывая статически импортированные методы.Я также попытался превратить мой метод в public и static (все перестановки), но безуспешно - мне пришлось его переименовать.

Есть какая-то причина, почему он так себя ведет?Я не смог найти ссылки на это поведение в документации.

Ответы [ 4 ]

3 голосов
/ 06 июля 2011

То, что вы наблюдали, зовет Затенение .Когда два типа в Java имеют одинаковое простое имя, один из них будет затенять другой.затем затененный тип не может использоваться его простым именем.

Наиболее распространенный тип затенения - это параметр, позволяющий скрыть поле.обычно результат установки кода выглядит как setMyInt(int myInt) {this.myInt = myInt; }

Теперь давайте прочитаем соответствующую документацию :

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

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

1 голос
/ 06 июля 2011

Перегрузка и перезапись работает в дереве наследования.Но статический импорт не создает наследство.

Если вы хотите использовать assertEquals из junit в своем собственном методе assertEquals, вы должны квалифицировать его с помощью className, например, Assert.assertEquals.

Useнестатический импорт org.junit.Assert.

0 голосов
/ 07 июля 2011

Это имеет смысл.Предположим, что javac делает то, что вы хотите, он выбирает ваш assertEquals(MyObj, MyObj) метод сегодня.Что если завтра org.junit.Assert добавит свой собственный метод assertEquals(MyObj, MyObj)?Значение заклинания assertEquals(mo1,mo2) резко изменилось без вашего ведома.

Под вопросом стоит значение имени assertEquals.Javac должен решить, что это имя метода (ов) в org.junit.Assert.Только после этого он может выполнять разрешение перегрузки методов: изучить все методы в org.junit.Assert с именем assertEquals, выбрать наиболее подходящий.

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

Если во время компиляции нет никаких сомнений в том, что разработчик принадлежит к какому классу принадлежит метод, класс все еще может быть перегружен методом завтра, поэтому изменяется вызываемый целевой метод.Однако, поскольку это делается одним и тем же классом, мы можем считать его ответственным.Например, если org.junit.Assert решит добавить новый метод assertEquals(MyObj, MyObj), он должен знать, что некоторые предыдущие вызовы assertEquals(Object,Object) теперь перенаправлены в новый метод, и он должен убедиться, что нет изменений семантики, которые нарушатсайты вызова.

0 голосов
/ 06 июля 2011

Вы наткнулись на метод, скрывающий , где присутствие локального метода «скрывает» один от другого класса (часто суперкласса).

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

Как стиль, я предпочитаю импортировать класс и использовать TheirClass.method() в моем коде.Это дает понять, что метод не является локальным методом, и одним из признаков хорошего кода является ясность.

Я рекомендую вам import org.junit.Assert и используйте Assert.assertEquals(...).

...