Java: более общая сигнатура метода дает мне NoSuchMethodError - PullRequest
8 голосов
/ 12 мая 2011

Существует баночка, которую при создании он должен был использовать метод MyClass.doSomething(List). Этот метод был изменен на doSomething(Collection) и помещен в другую банку (только для этого класса).

Я положил 2-ую банку перед моей первой банкой в ​​пути к классам, но когда код в моей первой банке вызывает MyClass.doSomething() со списком, я все равно получаю

java.lang.NoSuchMethodError: MyClass.doSomething(Ljava/util/List;)Ljava/util/List;

Как это возможно? Муравей был использован для компиляции банок.

Ответы [ 2 ]

11 голосов
/ 12 мая 2011

Существует важное различие между исходной совместимостью и двоичной совместимостью.

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

Совместимость с исходным кодом делает not автоматически подразумевает двоичную совместимость, как вы уже видели.

Когда исходный код компилируется, определенная сигнатура метода, которая должна быть вызвана, определяется компилятором и сохраняется в файле .class (в данном случае это doSomething(List)).

Если класс изменяется и метод doSomething(List) удаляется при добавлении doSomething(Collection), то совместимость с исходным кодом сохраняется (поскольку вы можете просто скомпилировать тот же код дляновый класс), но двоичная совместимость потеряна!

Спецификация языка Java имеет Весь раздел о двоичной совместимости .

Подводя итог: при изменении типа аргумента метода на более общий тип (обычно) совместим с источником, он не двоично совместим.

Если вы хотите сохранить двоичную совместимость, то изменение должно выглядеть следующим образом:

public void doSomething(Collection foo) { ... } // original method with changed argument type

public void doSomething(List foo) { // new binary compatibility method, just delegates to original one
  doSomething((Collection) foo);
}
4 голосов
/ 12 мая 2011

В общем случае, если вы получаете NoSuchMethodError, это означает, что версия целевого класса, используемая во время выполнения, отличается от версии целевого класса, с которой был вызван вызывающий класс.В вашем случае это не удивительная ошибка;Байт-код в первом JAR-файле все еще компилируется с учетом существования метода, который принимает List, , которого не существует .

Это может быть связано с добавочной компиляцией Ant, которая не замечает, что зависимые классы изменились, или что-то подобное.

Если вы делаете чистую перестройку всего проекта (ну, по крайней мере, оба JAR-файла)Вы упомянули, что эта проблема должна быть решена, так как компилятор создает байт-код, который вызывает новую doSomething подпись.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...