Почему некоторые методы библиотеки Java делегируют собственный метод с почти идентичной подписью?
После углубления в исходный код библиотеки JRE я заметил необычно распространенную структуру кода, например:
public int foo(double bar) {
return foo0(bar);
}
private native int foo0(double bar);
В чем заключается цель этого шаблона кода и почему он используется вместо простого раскрытия основного метода native как общедоступного?
Ответы
Ответ 1
Нативная версия - это просто деталь реализации.
Этот шаблон отделяет открытый интерфейс метода от фактической реализации.
Я вижу по крайней мере 5 причин, почему это полезно:
- Цель теста (вы можете высмеять вызов метода java)
- альтернативная реализация: конкретная версия java-библиотеки может реализовать этот метод в чистой форме java без вызова собственной реализации (общая в swing-коде).
- обратная совместимость: если в новой версии метод принимает некоторые дополнительные параметры, исходная сигнатура метода java может быть сохранена и адаптирована адаптивная адаптация.
- проверка ввода-вывода: большую часть времени, прежде чем вызывать собственную версию, код Java будет выполнять некоторые проверки входных параметров и, если необходимо, генерировать исключение.
- Изоляция: количество методов, непосредственно использующих собственный код, ограничено, что позволяет больше изменений во внутренней структуре кода.
Вероятно, вы можете найти больше преимуществ.
Ответ 2
private native int foo(double bar);
Итак, в конце концов, это должно вызвать функцию С++ для ее реализации. В частности, это вызовет функцию с именем вроде:
Java_MyClass_foo
Что произойдет, если есть несколько собственных методов foo с разными сигнатурами? Осложнения. Если вы это сделаете, Java добавит информацию о типе в имя метода, который он ищет. Но это проще, если вы придерживаетесь неперегруженных методов.
public int foo(double bar) {
return foo0(bar);
}
private native int foo0(double bar);
foo0
было присвоено уникальное имя, никогда не должно быть причин добавить еще один foo0
. Это сохраняет реализацию С++ простой, ей никогда не приходится иметь дело с искаженными именами. Даже если foo в конечном итоге получит перегрузку, он вызовет foo1
вместо foo0
, а реализация С++ JNI не будет иметь дело с дополнительными осложнениями перегрузки.