2011-07-06 3 views
6

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

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 (все перестановки), но без успеха - мне пришлось переименовать его.

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

+1

Что мешает вам изменить подпись (или даже имя) внутреннего метода? – spot35

+1

@DomSelvon, Изменение подписи не помогает. О имени метода - меня не останавливает - вопрос теперь чисто для знания (уже изменил имя) – RonK

ответ

3

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

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

Теперь давайте читать relevant documentation:

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

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

+0

Это действительно похоже на случай - хотя я должен признаться, что после прочтения как вашего объяснения, так и Spec - я до сих пор не понимаю, почему один метод с определенной сигнатурой тени другой – RonK

+0

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

+0

Или вы имели в виду, что вы все еще не понимаете, почему он предпочитает один метод над другим? Это просто внимательно читает и применяет правила в спецификации. В целом вы можете сказать, что он предпочитает местный материал, затем класс, затем унаследован, затем импортируется, а затем импортируется по требованию. – Dorus

1

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

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

Используйте нестатический импорт org.junit.Assert.

+0

Это, кажется, лучший ответ без изменения имени настраиваемого метода. – Joseph

0

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

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

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

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

+0

Этот стиль позволяет понять, откуда этот метод. Но что касается ясности, важный вопрос: «Что он делает?» и с этим уважением вы примерно удвоили количество символов, не уточняя ничего. –

+0

Как указал Дорус, это [_shadowing_] (http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.4.1), а не _hiding_, потому что Метод Assert.assertEquals' не наследуется. –

0

Это имеет смысл. Предположим, что 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) теперь перенаправляются на новый метод, и он должен убедиться, что нет изменений семантики, которые нарушат сайты вызовов.

 Смежные вопросы

  • Нет связанных вопросов^_^