Що робить JVM настільки універсальним для підтримки такої кількості мов JVM?


18

JVM підтримує так багато мов, крім Java, як Groovy,Clojure,Scalaі т.д., які є функціональними мовами на відміну від Java (я маю на увазі Java до версії 8, де Lambda'sвони не підтримуються), які не підтримують функціональні можливості. На високому рівні те, що робить JVM настільки універсальним, що він може підтримувати як об'єктно-орієнтовані, так і функціональні мови?


"Groovy, Clojure, Scala тощо, які функціональні". Деякі з них є більш функціональними, ніж інші. Я б використав шкалу з Groovy найменш funcional і Clojure найбільше, а Scala посередині.
Vorg van Geir

Відповіді:


37

Порівняно з іншими ВМ, JVM насправді не особливо універсальний . Він безпосередньо підтримує статично набраний OO. Для всього іншого ви повинні бачити, які деталі ви можете використовувати, і як ви можете будувати все інше, що потрібна вашій мові.

Наприклад, поки Java 7 не представила invokedynamicбайт-код, було дуже важко реалізувати динамічно набрану мову OO на JVM - вам довелося використовувати складні обхідні шляхи, які були поганими для продуктивності та призводили до жахливо роздутих слідів стека.

І все-таки на динамічному JVM було впроваджено купу динамічних мов (Groovy, Jython, JRuby).

Не тому, що JVM настільки універсальний, а тому, що він настільки поширений, і тому, що він має дуже зрілі, добре підтримувані та високоефективні реалізації.

І, можливо, навіть важливіше, оскільки там існує величезна кількість Java-коду, яка робить майже все, і якщо ваша мова працює на JVM, ви можете легко запропонувати засоби для інтеграції з цим кодом. В основному, ваша мова працює на JVM - це версія 21 століття, яка пропонує сумісність з C.


Гарна відповідь (+1). Останній пункт, про який ви згадуєте, - IMHO також відповідає за популярність Java як мови: врешті-решт, наявність величезної кількості коду, яку ви можете повторно використовувати безкоштовно, може заощадити набагато більше часу, ніж можливість користуватися останньою і модною мовою особливості.
Джорджіо

4

JVM був написаний, щоб в основному діяти як процесор, є набір інструкцій, схожих на збірку, що VM працює під назвою байт-коди. Якщо ви можете написати компілятор, який генерує дійсний набір байт-кодів, то JVM може запустити їх.

У Вікіпедії є список байткодів:

http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings

а також пояснення того, як JVM завантажує байтові коди:

http://en.wikipedia.org/wiki/Java_virtual_machine

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


1
Те ж саме стосується всіх інших VM там: YARV Ruby VM, Rubinius Ruby VM, CPython VM (який зрештою був попереднім JVM), Папуга, різні VM Smalltalk та Lisp, і звичайно Pascal P- Кодова система, за якою моделюється JVM.
Йорг W Міттаг

Погодився, JVM, безумовно, не перший VM там. Я думаю, що JVM популярний для інших мов, тому що Java популярна, VM активно розвинений і добре задокументований.
sasbury

2

Додам, що JVM підтримує чітко визначену і досить пристойну модель пам'яті ( JMM ), що означає хорошу підтримку послідовного (хоча і низького рівня) поведінки з нарізкою. Він також має потужний компілятор Just In Time (не більш корисний для динамічних мов завдяки MethodHandles та виклику динаміки).

І останнє, але не менш важливе значення - це підсистема JVM Garbage Collection, яка (за допомогою правильної настройки) керує пам’яттю для вас незалежно від мови, що знаходиться на вершині.


JMM - одна з моїх найменш улюблених речей щодо Java. Я прихильник ефективно незмінних даних (наприклад, масивів, вміст яких ніколи не змінюватиметься після того, як їх буде видно в інших потоках), але мені надано твердження, як someField = new int[]{42};єдині способи гарантувати, що будь-який потік, який бачить новий масив, побачить значення 42 повинні або зробити поле finalабо volatile. Якщо поле геніально генерується, але до нього звертаються часто, тому воно finalне працюватиме, а його створення volatileможе накладати непотрібне покарання за синхронізацію щоразу, коли до нього звертаються. Навіть найслабша модель .NET ...
supercat

... код може вимагати, щоб популяція масиву сталася перед сховищем посилання. Інші потоки, які читають поле, можуть або не бачать посилання на новий масив, але самі собі не будуть впевнені, що якщо вони побачать новий масив, вони побачать його вміст.
supercat

1

Ключовим елементом у цьому є відокремлення компіляції від фази виконання. Цим можна писати інші компілятори, що компілюють інші мови в байт-код.

Байт-код там діє аналогічно машинному коду процесора - у вас є всі невеликі операції, необхідні для запуску програми - ви можете отримати змінну, робити математику на ній, мати умовні операції тощо.

Java також не особлива. У Java існування декількох мов навіть не було ціллю дизайну, на відміну від інших віртуальних машин. Для Microsoft .Net CIL можливість запускати декілька мов (C #, VB.Net, ...) була ключовим елементом дизайну, також ParrotVM з проекту Perl6 мав бути загальним VM.

Для задоволення від цього я колись створив доказ того, що навіть Zend Engine PHP це дозволить.

І, чесно кажучи, це не є новим - навіть на реальному апаратному забезпеченні ви можете працювати на декількох мовах - наприклад, C або Fortran.

Відмінність цього відокремлення від компіляції та виконання - це інтерпретації, що містяться в кліссі, як і деякі форми Basic, скриптів оболонки тощо. Вони часто працюють так, що вони виконують код більш-менш рядково за рядком, не приводячи його в безпосередню форму по середині.


1

JVM - це перша віртуальна машина, яку я знаю, яка поєднала збирання сміття, продуктивність та працездатну модель пісочниці. Поява багатьох мов для підтримки JVM, мабуть, не стільки результат її «універсальності», скільки швидше те, що в мові Java відсутні деякі суттєві особливості, яких бажають люди в мові програмування. Наприклад, хоча більшість машинних мов мають лише півдюжини або близько таких типів даних (наприклад, байт, півслова, слово, подвійне слово, плаваючий одноточний плавець і плавучий подвійний точність), переважна більшість мов програмування дозволяє коду використовувати код довільна кількість визначених користувачем типів даних. JVM розпізнає кілька примітивних типів, подібних до типових на машині, плюс ще один тип: Promiscuous Reference Object. Мова Java також розпізнає ці примітиви, та промісні посилання на об'єкти. Хоча змінна може бути обмежена не містити посилань на що-небудь, що не є певним класом, мова не робить відмінностей між будь-яким із наведених нижче типів поля типуList<String>який може містити MyThingклас екземпляра MyClass:

  • Посилання на якийсь код, як відомо, є незмінною реалізацією List<String>

  • Посилання на екземпляр типу змінного списку, який ніколи не буде піддаватися впливу нічого, що може його мутувати.

  • Посилання на список, що змінюється, на який, окрім під час виконання MyThingsросійських методів, жодна інша посилання не могла існувати ніде у Всесвіті.

  • Посилання на список, що змінюється, який належить якомусь іншому об'єкту , який цей інший об'єкт хотів би MyThingвикористати певним чином.

  • Посилання на змінний список, який MyThingє його власником, але який також піддався впливу деяких інших об'єктів, щоб вони могли щось із цим зробити.

Хоча всі ці поля могли мати тип List<String>, вони містять дуже різні речі. Експресивна мова може дозволяти розрізняти ці значення, але Java цього не робить. Оскільки мова може надавати значення таким речам (принаймні поза загальним контекстом) та працювати на JVM, це залишає багато місця для мов, орієнтованих на JVM, для вираження понять, які Java не може.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.