Điều gì làm cho JVM rất linh hoạt để hỗ trợ nhiều ngôn ngữ JVM?


18

JVM hỗ trợ rất nhiều ngôn ngữ khác ngoài Java như Groovy,Clojure,Scalavv mà là ngôn ngữ chức năng không giống như Java (tôi đề cập đến Java trước khi phiên bản 8 nơi Lambda'skhông được hỗ trợ) mà không hỗ trợ chức năng capabilities.On một mức độ cao những gì làm cho JVM nên linh hoạt mà nó có thể hỗ trợ cả đối tượng hướng đối tượng cũng như ngôn ngữ chức năng?


"Groovy, Clojure, Scala, vv là những chức năng". Một số trong số đó là nhiều chức năng hơn những người khác. Tôi sẽ sử dụng một thang đo với Groovy ít chức năng nhất và Clojure nhiều nhất, với Scala ở giữa.
Vorg van Geir

Câu trả lời:


37

So với các máy ảo khác, JVM thực sự không linh hoạt . Nó trực tiếp hỗ trợ gõ tĩnh OO. Đối với mọi thứ khác, bạn phải xem những phần nào bạn có thể sử dụng và cách bạn có thể xây dựng mọi thứ khác mà ngôn ngữ của bạn cần trên các phần đó.

Ví dụ, cho đến khi Java 7 giới thiệu invokedynamicmã byte, rất khó để thực hiện ngôn ngữ OO được gõ động trên JVM - bạn phải sử dụng các cách giải quyết phức tạp có hại cho hiệu năng và dẫn đến dấu vết ngăn xếp khủng khiếp.

Chưa hết, một loạt các ngôn ngữ động (Groovy, Jython, JRuby trong số các ngôn ngữ khác) đã được triển khai trên JVM trước đó.

Không phải vì JVM rất linh hoạt, mà bởi vì nó rất phổ biến và bởi vì nó có các triển khai rất thành thục, được hỗ trợ tốt và có hiệu suất cao.

Và, có lẽ thậm chí còn quan trọng hơn, vì có một lượng lớn mã Java ngoài kia đang làm khá nhiều thứ và nếu ngôn ngữ của bạn chạy trên JVM, bạn có thể dễ dàng cung cấp các phương tiện để tích hợp với mã đó. Về cơ bản, việc ngôn ngữ của bạn chạy trên JVM là phiên bản thế kỷ 21 cung cấp khả năng tương tác với C.


Câu trả lời hay (+1). Điểm cuối cùng mà bạn đề cập là IMHO cũng chịu trách nhiệm về sự phổ biến của Java như một ngôn ngữ: cuối cùng, việc có một lượng lớn mã bạn có thể sử dụng lại miễn phí có thể giúp bạn tiết kiệm nhiều thời gian hơn so với việc có thể sử dụng ngôn ngữ mới nhất và thời trang nhất đặc trưng.
Giorgio

4

JVM được viết để cơ bản hoạt động như một CPU, có một tập hợp các hướng dẫn, giống như lắp ráp, mà VM chạy được gọi là mã byte. Nếu bạn có thể viết một trình biên dịch tạo ra một tập hợp mã byte hợp lệ, thì JVM có thể chạy chúng.

Wikipedia có một danh sách các mã byte:

http://en.wikipedia.org/wiki/Java_bytecode_in cản_listings

cũng như giải thích về cách JVM tải mã byte:

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

Bằng cách sử dụng mã byte kiểu gọi, một ngôn ngữ chức năng có thể thực thi mã, bất kể nguồn trông như thế nào. Ngoài ra, với việc bổ sung invokevirtual, các triển khai ngôn ngữ như jruby đã mang lại sự linh hoạt với cách chúng chạy.


1
Điều tương tự cũng đúng với mọi VM khác ngoài đó: YARV Ruby VM, Rubinius Ruby VM, CPython VM (mà sau tất cả trước JVM), Parrot, các Smalltalk và Lisp VM khác nhau, và dĩ nhiên là Pascal P- Hệ thống mã, sau đó JVM được mô hình hóa.
Jörg W Mittag

Đồng ý, JVM chắc chắn không phải là VM đầu tiên ngoài kia. Tôi nghĩ rằng JVM là phổ biến cho các ngôn ngữ khác vì Java là phổ biến, VM được tích cực phát triển và tài liệu tốt.
sasbury

2

Tôi sẽ thêm rằng JVM hỗ trợ Mô hình bộ nhớ ( JMM ) được xác định rõ và khá tốt , có nghĩa là hỗ trợ tốt cho hành vi phân luồng nhất quán (mặc dù ở mức độ thấp). Nó cũng có một trình biên dịch Just In Time mạnh mẽ (không còn hữu ích cho các ngôn ngữ động nhờ Phương thức và inv invocate).

Cuối cùng nhưng không kém phần quan trọng là hệ thống phụ Bộ sưu tập rác của JVM, với (điều chỉnh đúng) quản lý bộ nhớ cho bạn bất kể ngôn ngữ trên đầu trang.


JMM là một trong những điều yêu thích nhất của tôi về Java. Tôi là người hâm mộ dữ liệu bất biến hiệu quả (ví dụ: mảng có nội dung sẽ không bao giờ thay đổi sau khi chúng hiển thị với các luồng khác), nhưng đưa ra một tuyên bố như someField = new int[]{42};cách duy nhất để đảm bảo rằng bất kỳ luồng nào nhìn thấy mảng mới sẽ thấy giá trị 42 là để làm cho lĩnh vực finalhoặc volatile. Nếu trường được tạo một cách lười biếng nhưng được truy cập thường xuyên, làm cho nó finalkhông hoạt động và khiến nó volatilecó thể bị phạt đồng bộ hóa không cần thiết mỗi khi nó được truy cập. Ngay cả trong mô hình .NET lỏng lẻo nhất ...
supercat

... mã có thể yêu cầu dân số của mảng xảy ra trước khi lưu trữ tham chiếu. Các luồng khác đọc trường có thể hoặc không thể thấy tham chiếu đến mảng mới, nhưng sẽ không mất phí khi họ thấy mảng mới, họ sẽ thấy nội dung của nó.
4/2/2015

1

Yếu tố chính trong việc này là tách phần biên dịch khỏi pha thực thi. Bằng cách này, có thể viết các trình biên dịch khác biên dịch các ngôn ngữ khác sang mã byte.

Mã byte hoạt động tương tự như mã máy của CPU - bạn có tất cả các hoạt động nhỏ cần thiết để chạy chương trình - bạn có thể nhận được một biến, làm toán trên nó, có các hoạt động có điều kiện, v.v.

Java cũng không đặc biệt. Trong Java, sự tồn tại của nhiều ngôn ngữ thậm chí không phải là mục tiêu thiết kế, không giống như các máy ảo khác. Đối với Microsoft .Net CIL , khả năng chạy nhiều ngôn ngữ (C #, VB.Net, ...) là một yếu tố thiết kế chính, cũng là ParrotVM từ dự án Perl6 nhằm trở thành một VM chung.

Để giải trí, tôi đã từng tạo ra một bằng chứng rằng ngay cả Zend Engine của PHP cũng cho phép điều đó.

Và thật lòng mà nói đây không phải là bất cứ điều gì mới - ngay cả trên phần cứng thực, bạn có thể chạy nhiều ngôn ngữ - tức là C hoặc Fortran.

Sự khác biệt của sự tách biệt này khỏi quá trình biên dịch và thực thi là các trình thông dịch clssic, như một số dạng Basic, shell script, v.v. chúng thường hoạt động theo cách chúng thực thi mã ít nhiều theo một dòng theo cách mà không đưa nó vào dạng ngay lập tức ở giữa.


1

JVM là máy ảo đầu tiên tôi biết về việc kết hợp bộ sưu tập rác, hiệu năng và mô hình hộp cát hoàn toàn khả thi. Sự xuất hiện của nhiều ngôn ngữ để hỗ trợ JVM có lẽ không phải là kết quả của tính "linh hoạt" của nó, mà thực tế là ngôn ngữ Java thiếu một số tính năng quan trọng mà mọi người muốn có trong ngôn ngữ lập trình. Ví dụ, trong khi hầu hết các ngôn ngữ máy chỉ có nửa tá loại dữ liệu (ví dụ: byte, nửa từ, từ, từ kép, float chính xác đơn và float chính xác kép), đại đa số các ngôn ngữ lập trình cho phép sử dụng mã một số lượng tùy ý các loại dữ liệu do người dùng định nghĩa. JVM nhận ra một vài loại nguyên thủy tương tự như các loại trên một máy điển hình, cộng với một loại nữa: Tham chiếu đối tượng lăng nhăng. Ngôn ngữ Java cũng nhận ra những nguyên thủy đó, và tài liệu tham khảo đối tượng lăng nhăng. Mặc dù một biến có thể bị hạn chế không giữ tham chiếu đến bất kỳ thứ gì không phải là một lớp cụ thể, ngôn ngữ không tạo ra sự khác biệt giữa bất kỳ loại trường nào sau đâyList<String>có thể được tổ chức bởi MyThinglớp thể hiện MyClass:

  • Tham chiếu đến một cái gì đó biết mã là một triển khai bất biến của List<String>

  • Một tham chiếu đến một thể hiện của một loại danh sách có thể thay đổi sẽ không bao giờ được tiếp xúc với bất cứ điều gì có thể làm thay đổi nó.

  • Một tham chiếu đến một danh sách có thể thay đổi mà ngoại trừ trong quá trình thực thi các MyThingsphương thức, không có tham chiếu nào khác có thể tồn tại ở bất cứ đâu trong vũ trụ.

  • Một tham chiếu đến một danh sách có thể thay đổi được sở hữu bởi một số đối tượng khác , mà đối tượng khác muốn MyThingsử dụng trong một số thời trang.

  • Một tham chiếu đến một danh sách có thể thay đổi MyThingsở hữu, nhưng nó cũng đã tiếp xúc với một số đối tượng khác để họ có thể làm gì đó với nó.

Mặc dù tất cả các lĩnh vực đó có thể có loại List<String>, chúng giữ những thứ rất khác nhau. Một ngôn ngữ biểu cảm có thể cho phép phân biệt giữa các nghĩa đó, nhưng Java thì không. Do một ngôn ngữ có thể gắn ý nghĩa với những thứ đó (ít nhất là bên ngoài bối cảnh chung) và chạy trên JVM, nên sẽ có rất nhiều chỗ cho các ngôn ngữ được nhắm mục tiêu JVM để diễn tả các khái niệm mà Java không thể.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.