2016-08-15 10 views
62

Po zagłębiając się w kodzie źródłowym biblioteki JRE, zauważyłem dziwnie wspólną strukturę kodu, na przykład:Dlaczego niektóre metody biblioteki Java delegują do natywnej metody z niemal identycznym podpisem?

public int foo(double bar) { 
    return foo0(bar); 
} 

private native int foo0(double bar); 

Jaki jest cel tego kodu wzorem i dlaczego jest używany zamiast po prostu wystawiając podstawową metodę rodzimą jako publiczną?

+10

Dobre pytanie. Musiałbyś zapytać projektantów języka. Być może kiedy zaprojektowano niektóre z wczesnych bibliotek, nie zdecydowano jeszcze, czy możliwe będzie zastąpienie natywnej metody. Tylko zgaduję. –

+2

Definiowanie "wielu" jest subiektywne. – Raedwald

+13

Jako ktoś, kto napisał dużo kodu JNI, muszę powiedzieć, że używam tego samego wzoru konsekwentnie - last but not least, fajnie jest szybko dodać trochę 'System.out.println (" Metoda jest wywoływana, więc dlaczego heck nie działa!?!?! ");' w części Java, bez konieczności przekompilowania natywnego kodu. – Marco13

Odpowiedz

47

Wersja natywna to tylko szczegół implementacji.

Ten wzór oddziela publiczny interfejs metody od rzeczywistej implementacji.

widzę co najmniej 5 powodów, dla których jest to przydatne:

  • Celem testu (można mock wywołanie metody Java)
  • alternatywą realizacji: konkretnej wersji biblioteki Java mogą wdrożyć tę metodę w czysta forma Java bez wywołania natywnej implementacji (często w kodzie huśtawki).
  • kompatybilność wsteczna: jeśli w nowej wersji metoda akceptuje dodatkowe parametry, można zachować oryginalny podpis metody java i dostosować implementację natywną.
  • sprawdzanie poprawności danych wejściowych/wyjściowych: większość czasu przed wywołaniem wersji natywnej kod java wykonuje pewne sprawdzenia parametrów wejściowych i wyrzuca wyjątek, jeśli jest to konieczne.
  • Izolacja: liczba metod, które bezpośrednio używają natywnego kodu jest ograniczona, umożliwiając więcej zmian w wewnętrznej strukturze kodu.

Prawdopodobnie możesz znaleźć więcej zalet.

+16

Nie widzę, w jaki sposób dodatkowa warstwa indeksu pomaga w tym wszystkim. 1) Nie myślę o "rodzimych" śrubach z kpiną.2) Różne implementacje Javy mogą tworzyć różne metody "natywne" bez wzajemnego konfliktu. 3) Jeśli metoda akceptuje dodatkowe parametry w nowej wersji (mało prawdopodobne, które przełamałyby kompatybilność wsteczną), wymagane zmiany są w przybliżeniu takie same. 4) Nie wiem, czy to rzeczywiście prawda, a co z tymi, w których metoda inna niż "zwyczajna" po prostu przekazuje bezpośrednio "native"? ... – user2357112

+0

5) Ograniczenie liczby metod, które bezpośrednio wywołują "natywną" metodę, nie pozwala na więcej zmian w strukturze kodu. – user2357112

+22

Rzeczywiście, zgodnie z http://stackoverflow.com/questions/10940502/is-it-possible-to-override-a- native-method-in-a-java-class-in-android-dalvik wydaje się, że natywne słowo kluczowe nie jest częścią sygnatury metody, więc ta odpowiedź nie ma sensu. –

14
private native int foo(double bar); 

Tak więc, w końcu to musi wywołać funkcję C++ dla jego implementacji. W szczególności będzie to skończyć wywołanie funkcji z czymś nazwy takie jak:

Java_MyClass_foo 

Co się stanie, jeśli istnieje wiele metod natywnych Foo z różnych podpisów? Komplikacje. Jeśli to zrobisz, Java doda informacje o typie do nazwy szukanej metody. Ale po prostu łatwiej jest trzymać się metod nieprzeciążonych.

public int foo(double bar) { 
    return foo0(bar); 
} 

private native int foo0(double bar); 

foo0 nadano unikalną nazwę, nigdy nie powinno być powodem, aby dodać kolejną foo0. Dzięki temu implementacja C++ staje się prosta, nigdy nie ma do czynienia z zniekształconymi nazwami. Nawet jeśli foo ostatecznie zyska przeciążenie, zadzwoni pod numer foo1 zamiast foo0, a implementacja JNI C++ nie będzie musiała radzić sobie z dodatkowymi komplikacjami przeciążania.

+2

To może być powód, ale ** bardzo mało prawdopodobne. Praktycznie nie ma żadnych komplikacji. W szczególności nie będzie ** żadnego przeciążenia **: Generator nagłówka 'javah' wykryje niejednoznaczności/przeciążone metody i zrobi trochę [wymazanie nazwy] (https://en.wikipedia.org/wiki/Name_mangling), aby utworzyć podpisy unikalne. (Musi, tak naprawdę, ponieważ JNI to zwykły C, a nie C++). – Marco13

+0

@ Marco13, Zauważyłem wyraźnie, że w mojej odpowiedzi "Java doda informacje o typie do nazwy metody, której szuka" i opowiadała o zniekształconych nazwach. –

Powiązane problemy