Czy kod Javy 8 można skompilować do działania na Javie 7 JVM?
Java 8 wprowadza ważne nowe funkcje językowe, takie jak wyrażenia lambda.
Czy tym zmianom w języku towarzyszą tak znaczące zmiany w skompilowanym kodzie bajtowym, które uniemożliwiłyby jego uruchomienie na maszynie wirtualnej Java 7 bez użycia retrotranslatora?
5 answers
Nie, użycie funkcji 1.8 w kodzie źródłowym wymaga kierowania na maszynę wirtualną 1.8. Po prostu próbowałem nowego wydania Javy 8 i próbowałem kompilować z -target 1.7 -source 1.8
, A kompilator odmawia:
$ javac Test -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-03-18 22:30:24
Metody domyślne wymagają takich zmian w kodzie bajtowym i JVM, które byłyby niemożliwe do wykonania w Javie 7. Weryfikator kodu bajtowego w Java 7 i niżej odrzuci interfejsy z ciałami metod (z wyjątkiem metody inicjalizacji statycznej). Próba emulowania domyślnych metod ze statycznymi metodami po stronie wywołującej nie da takich samych wyników, ponieważ domyślne metody mogą być nadpisywane w podklasach. Retrolambda ma ograniczone wsparcie dla backportowania domyślnych metod, ale nigdy nie może być w pełni backportowany, ponieważ naprawdę wymaga nowych funkcji JVM.
Lambda może działać na Javie 7 tak, jak jest, jeśli potrzebne klasy API po prostu tam istnieją. Instrukcja invokedynamic istnieje w Javie 7, ale możliwe byłoby zaimplementowanie lambda w taki sposób, że generuje ona klasy lambda w czasie kompilacji (wczesne kompilacje JDK 8 robiły to w ten sposób). (Oracle zdecydowało się użyć invokedynamic dla Lambda do przyszłych proofingu; może jeden day JVM będzie miał funkcje pierwszej klasy, więc wtedy invokedynamic może być zmieniony, aby używać ich zamiast generować klasę dla każdego lambda, poprawiając w ten sposób wydajność.) Retrolambda przetwarza wszystkie wywołane instrukcje i zastępuje je anonimowymi klasami; to samo, co robi Java 8 podczas wykonywania, gdy lamdba wywołane jest po raz pierwszy.
Powtarzanie adnotacji jest tylko cukrem składniowym. Są zgodne bajtowo z poprzednimi wersje. W Javie 7 wystarczy zaimplementować samodzielnie metody pomocnicze (np. getAnnotationsByType), które ukrywają szczegóły implementacji adnotacji kontenera, która zawiera powtarzające się adnotacje.
AFAIK, adnotacje typu istnieją tylko w czasie kompilacji, więc nie powinny wymagać zmian kodu bajtowego, więc wystarczy zmienić numer wersji kodu bajtowego klas skompilowanych w Javie 8, aby działały na Javie 7.
Parametr metody nazwy istnieją w bajtowym kodzie z Javą 7, więc jest to również zgodne. Można uzyskać do nich dostęp, odczytując kod bajtowy metody i patrząc na nazwy lokalnych zmiennych w informacji debugowania metody. Na przykład Spring Framework robi dokładnie to, aby zaimplementować @PathVariable , więc prawdopodobnie istnieje metoda biblioteczna, którą możesz wywołać. Ponieważ abstrakcyjne metody interfejsu nie mają ciała metody, informacje o debugowaniu nie istnieją dla metod interfejsu w Javie 7, a AFAIK ani na Javie 8.
Inne nowe funkcje to głównie nowe interfejsy API, ulepszenia hotspotu i narzędzi. Niektóre z nowych interfejsów API są dostępne jako biblioteki stron trzecich (np. ThreeTen-Backport i streamsupport ).
Summa summarum, domyślne metody wymagają nowych funkcji JVM, ale inne funkcje języka nie. jeśli chcesz ich użyć, musisz skompilować kod w Javie 8, a następnie przekształcić bajt za pomocą Retrolambda do Javy 5/6/7 format. Co najmniej wersja kodu bajtowego musi zostać zmieniona, a javac wyłącza -source 1.8 -target 1.7
, więc wymagany jest retrotranslator.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-11-03 00:16:28
Z tego co wiem żadna z tych zmian w JDK 8 nie wymagała dodania nowych bajtekodów. Część oprzyrządowania lambda jest wykonywana przy użyciu invokeDynamic
(które już istnieją w JDK 7). Tak więc, z punktu widzenia zestawu instrukcji JVM, nic nie powinno sprawić, że baza kodowa będzie niezgodna. Istnieje jednak wiele powiązanych z API i ulepszeń kompilatora, które mogłyby utrudnić kompilowanie/uruchamianie kodu z JDK 8 Pod poprzednimi JDK (ale nie próbowałem tego).
Może następujące materiał referencyjny może w jakiś sposób pomóc wzbogacić zrozumienie sposobu instrumentowania zmian związanych z lambda.
Wyjaśniają one szczegółowo, w jaki sposób rzeczy są oprzyrządowane pod maską. Być może znajdziesz tam odpowiedź na swoje pytania.Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-09-07 11:17:50
Jeśli chcesz użyć "retrotranslatora", wypróbuj doskonałą Retrolambdę Esko Luontola: https://github.com/orfjackal/retrolambda
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-05-17 09:39:19
Możesz zrobić -source 1.7 -target 1.7
wtedy się skompiluje. Ale nie skompiluje się, jeśli masz specyficzne funkcje java 8, takie jak lambdas
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-12-20 15:33:38