Теорія і практика Java: Використання можливостей мови Java 5 в попередніх версіях JDK (исходники), Різне, Програмування, статті

У версії Java 5 в мову було додано багато значних можливостей: generic “і, перераховуються типи, анотації, autoboxing, поліпшений цикл for. Однак багато груп розробки все ще прив’язані до JDK 1.4 або більш ранніх версій і можуть перебувати в такому стані ще деякий час. Проте ці розробники все-таки можуть використовувати ці корисні можливості мови, продовжуючи встановлювати додатки на ранні версії JVM. Повернувся після перерви Брайан Гетц в цій статті серії Теорія і практика Java покаже, як цього домогтися.


Після недавнього виходу Java 6.0 можна було б подумати, що можливості Java 5 вже стали стандартом. Але навіть зараз, коли я питаю програмістів, яку версію платформи Java вони використовують для розробки, звичайно тільки половина застосовує Java 5, а інша половина їм заздрить. Багато хто хотів би використовувати можливості мови, додані в Java 5, такі як generic “і та анотації, але в силу певних причин не можуть зробити цього.


Одна з категорій розробників, які не можуть скористатися перевагами функціональності Java 5, – це розробники компонентів, бібліотек і каркасів для розробки додатків. Справа в тому, що їх замовники, можливо, все ще використовують JDK 1.4 або більш ранні версії, а класи, скомпільовані під Java 5, не можуть бути завантажені JDK 1.4 і більш старими JVM. Тому використання можливостей мови Java 5 може привести до скорочення кола їх замовників, залишивши їм тільки компанії, вже перейшли на Java 5.


Інша група розробників, утримуватися від використання Java 5, – це програмісти, що працюють з Java EE. Багато груп розробників не хочуть використовувати Java 5 c Java EE 1.4 і більш ранніми версіями з побоювання, що Java 5 не буде підтримуватися виробником використовуваного ними сервера додатків. Так що пройде якийсь час, перш ніж такі проекти почнуть переходити на Java 5. Також, крім тимчасового розриву між специфікаціями Java EE 5 і Java SE 5, не факт, що комерційні контейнери Java EE 5 з’являться відразу ж після випуску нової версії специфікації. Компаніям зовсім не обов’язково оновлювати свої сервера додатків відразу після виходу нової версії, і навіть після поновлення сервера додатків може знадобитися час для сертифікації додатків на нову платформу.


Реалізація можливостей мови в Java 5


Можливості мови, додані в Java 5, – generic “і, перераховуються типи, анотації, autoboxing і поліпшений цикл for-не вимагають змін в наборі інструкцій JVM і практично повністю реалізовані в статичному компіляторі javac і бібліотеках класів. Коли компілятор виявляє використання generic “ов, він намагається перевірити, що забезпечується безпека типів, видаючи попередження” unchecked cast “(неперевірене перетворення), якщо не може це перевірити, а потім генерує байт код, повністю ідентичний байт-коду, отриманого з еквівалентного не-generic коду з перетвореннями і т.д. Точно також autoboxing і поліпшений цикл for – це просто “синтаксична лафа” для абсолютно еквівалентного, але більш довгого коду, а перераховуються типи компілюються у звичайні класи.


В теорії можна взяти класи, згенеровані javac, І завантажити їх у більш ранню JVM. Насправді це і було метою створення групи JSR 14, групи Java Community Process, що відповідає за generic “і. Проте інші проблеми (такі як збереження анотацій), змусили змінити версію файлу класу в Java 5 в порівнянні з Java 1.4, що не дозволяє завантажувати код, скомпільований для Java 5, в більш ранні версії JVM. Також деякі з можливостей мови, додані в Java 5, залежать від бібліотек Java 5. Якщо відкомпілювати клас командою javac -target 1.5 і спробувати завантажити його в більш ранню JVM, виникне помилка UnsupportedClassVersionError, Так як параметр -target 1.5 генерує класи з версією файлу класу рівною 49, а JDK 1.4 підтримує тільки версії файлів класів до 48.


Цикл for-each


Покращений цикл for, Іноді званий циклом for-each, Обробляється компілятором так, як якщо б програміст надав аналогічний цикл for в старому стилі. Цикл for-each дозволяє здійснювати ітерацію по елементах масиву або колекції. У прикладі 1 наведено синтаксис ітерації по колекції за допомогою циклу for-each.


Приклад 1. Цикл for-each





Collection<Foo> fooCollection = …
for (Foo f : fooCollection) {
doSomething(f);
}

Компілятор перетворить цей код в аналогічний цикл, який використовує ітератори, як показано в прикладі 2.


Приклад 2. Еквівалент коду в прикладі 1 з використанням итераторов





for (Iterator<Foo> iter=f.iterator(); f.hasNext();) {
Foo f = (Foo)iter.next();
doSomething(f);
}

Яким чином компілятор визначає, що у наданого аргументу є метод iteraror()? Архітектори компілятора javac могли б вмонтувати в нього розуміння framework “a для роботи з колекціями, але цей підхід міг призвести до непотрібних обмежень. Замість цього був створений новий інтерфейс java.lang.Iterable (Див. приклад 3), а класи колекцій були модифіковані так, щоб реалізовувати Iterable. В результаті класи-контейнери, навіть не побудовані на базових колекціях з framework “a, також можуть використовувати можливості нового циклу for-each. Але це створює залежність від бібліотеки класів Java 5, так як інтерфейс Iterable відсутня в бібліотеці JDK 1.4.


Приклад 3. Інтерфейс Iterable





public interface Iterable<T> {
Iterator<T> iterator();
}

Перераховуються типи і autoboxing


Також як і цикл for-each, Що перераховуються типи вимагають підтримки бібліотеки класів. Коли компілятор зустрічає перераховуються тип, він генерує клас, що успадковує бібліотечної класу java.lang.Enum. Але також як і Iterable, Клас Enum відсутня в бібліотеці класів JDK 1.4.


Аналогічно autoboxing використовує методи valueOf(), Додані в класи-оболонки для примітивних типів, такі як Integer. Якщо boxing вимагає перетворення з int в Integer, То замість виклику new Integer(int) компілятор генерує виклик Integer.valueOf(int). Ця реалізація методу valueOf() використовує шаблон flyweight для кешування об’єктів Integer для часто використовуваних цілих значень типу integer. Наприклад, реалізація Java 6 кешує integer значення від -128 до 127, що дозволяє продуктивність за рахунок усунення надмірного створення об’єктів. При цьому, як і у випадку Iterable і Enum, Метод valueOf() відсутня в бібліотеці класів JDK 1.4.


Varargs (методи із змінним числом аргументів)


Коли компілятор зустрічає метод, визначений зі списком параметрів змінної довжини, він перетворює його в метод, який приймає масив компонентів відповідного типу. Коли компілятор зустрічає виклик методу зі списком параметрів змінної довжини, то він упаковує ці елементи в масив.


Анотації


При визначенні анотації вона може бути оголошена з анотацією @Retention, Яка вказує, як компілятор повинен надходити з класами, методами або полями, які використовують цю анотацію. Передбачені політики збереження – SOURCE (Відкидати дані з анотації при компіляції), CLASS (Записувати анотації в файл класу), RUNTIME (Записувати анотації в файл класу і зберігати їх під час виконання, щоб до них можна було звертатися рефлексивним чином).


Інші залежно від бібліотек


До Java 5, коли компілятор зустрічав спробу скласти два рядки, він використовував допоміжний клас StringBuffer, Щоб виконати складання. В Java 5 і пізніших версіях замість цього він генерує виклики до нового класу StringBuilder, Який не представлений в JDK 1.4 і раніших бібліотеках класів.


Використання можливостей Java 5


Через залежності можливостей мови від бібліотек підтримки навіть якщо class-файли, створені компілятором Java 5, вдасться завантажити в попередню версію JVM, то виконати їх все одно не вийде через помилок при завантаженні класів. Однак подібні проблеми можна вирішити відповідним перетворенням байт-коду, так як відсутні класи не містять важливої ​​функціональності.


JSR 14


Під час розробки специфікації Java generic “ов та інших можливостей мови Java, доданих в Java 5, в компілятор javac була додана експериментальна підтримка, що дозволяє йому використовувати можливості мови Java 5 і генерувати байт-код, який можна запускати на JVM 1.4. Хоча ці можливості офіційно не підтримуються і навіть не задокументовані, вони використовуються в ряді проектів Open Source, щоб дозволити розробникам використовувати мовні можливості Java 5 і створювати JAR-файли, що працюють на більш ранніх JVM. Тепер, коли javac став Open Source-проектом, ці можливості можуть підтримуватися сторонніми розробниками. Щоб активувати ці можливості, можна запустити javac з параметрами -source 1.5 і -target jsr14.


Режим JSR 14 змушує компілятор javac генерувати JDK 1.4-сумісний байт-код, що володіє можливостями Java 5.



Використання режиму JSR 14 дозволяє писати код, який використовує generic “і, autoboxing і цикл for-each в легких випадках, яких достатньо для більшості проектів. Це зручна, хоча і не підтримувана, можливість; при цьому компілятор генерує максимально сумісний байт-код за один прохід.


Retroweaver


В Java 5 є мовні можливості, не підтримувані режимом JSR 14, наприклад, такі як Iterable і перераховуються типи. Альтернативний підхід, який застосовується в таких Open Source-проектах, як Retroweaver і Retrotranslator, пропонує генерувати байт-код, використовуючи параметр -target 1.5, І потім механічно перетворювати байт-код у формат, сумісний з JDK 1.4


Першою з’явилася утиліта Retroweaver, яка обробляє всі випадки, оброблювані javac -target JSR 14, а також надає ще кілька можливостей.



Retrotranslator


Як це часто трапляється в Open Source-співтоваристві, якщо проект перестає рухатися вперед, він оголошується “мертвим”, і його місце займає новий проект, навіть якщо перший проект тільки вирішив “відпочити”. Саме така історія сталася з Retroweaver – основний розробник проекту вирішив відпочити від нього, і його місце зайняв інший аналогічний проект – Retrotranslator. Retrotranslator пропонує такі ж можливості, як Retroweaver, і ще багато додаткових можливостей, спрямованих на підтримку важливих оновлень в бібліотеці класів Java 5.



І Retroweaver, і Retrotranslator можуть виконувати трансформацію байт-коду як статично (під час компіляції), так і динамічно (під час завантаження класів).


Висновок


У тих невезучих розробників, які не можуть використовувати нові можливості Java 5, – а таких розробників, на жаль, ще дуже багато, – є декілька шляхів, що дозволяють їм використовувати нові можливості і зберегти сумісність байт-коду з JDK 1.4 і більш старими версіями. Є не підтримується опція -target jsr14 компілятора javac, Що дозволяє генерувати JDK 1.4-сумісний байт-код для деяких можливостей Java 5, а також Open Source-проекти Retroweaver і Retrotranslator, що перетворюють більшість байт-коду Java 5 в Java 1.4-сумісний байт-код. Що б ви не вибрали, не забудьте виконати тестування з особливою ретельністю, щоб переконатися в повній сумісності.


Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*