Mã Java 8 có thể được biên dịch để chạy trên JVM Java 7 không?


163

Java 8 giới thiệu các tính năng ngôn ngữ mới quan trọng như biểu thức lambda.

Những thay đổi trong ngôn ngữ này có kèm theo những thay đổi quan trọng như vậy trong mã byte được biên dịch sẽ ngăn không cho nó chạy trên máy ảo Java 7 mà không sử dụng một số trình điều khiển lại không?


Câu trả lời:


146

Không, sử dụng các tính năng 1.8 trong mã nguồn của bạn yêu cầu bạn nhắm mục tiêu 1.8 VM. Tôi vừa thử bản phát hành Java 8 mới và đã thử biên dịch -target 1.7 -source 1.8và trình biên dịch từ chối:

$ javac Test -source 1.8 -target 1.7
javac: source release 1.8 requires target release 1.8

4
Không, tôi không nghĩ rằng nó sẽ. Java có một thị phần nhỏ trên thị trường máy tính để bàn, nhưng giữ cho thị phần nhỏ bé đó trong một nắm khá chặt chẽ. Nhưng nó cản trở việc áp dụng các phiên bản và tính năng mới. Tôi sẽ không thể sử dụng các tính năng Java 8 trong mã tôi viết khá lâu, vì tôi muốn tránh mọi người phải nâng cấp cài đặt Java cục bộ của họ.
JesperE

Tại sao? "Có" có nghĩa là Java 8 có thể được biên dịch để chạy trên máy ảo Java 7, không chính xác theo trình biên dịch Java 8.
JesperE

5
Bây giờ tôi thấy: "Không" của bạn trả lời tiêu đề của câu hỏi, không phải cơ thể của câu hỏi.
Abdull

58

Các phương thức mặc định yêu cầu các thay đổi như vậy đối với mã byte và JVM mà chúng không thể thực hiện được trên Java 7. Trình xác minh mã byte của Java 7 trở xuống sẽ từ chối các giao diện với các thân phương thức (ngoại trừ phương thức khởi tạo tĩnh). Cố gắng mô phỏng các phương thức mặc định bằng các phương thức tĩnh ở phía người gọi sẽ không tạo ra kết quả tương tự, bởi vì các phương thức mặc định có thể bị ghi đè trong các lớp con. Retrolambda đã hỗ trợ hạn chế cho việc nhập các phương thức mặc định, nhưng nó không bao giờ có thể được nhập hoàn toàn bởi vì nó thực sự đòi hỏi các tính năng JVM mới.

Lambdas có thể chạy trên Java 7, nếu các lớp API cần thiết chỉ tồn tại ở đó. Lệnh inv invocate tồn tại trên Java 7, nhưng có thể triển khai lambdas để nó tạo ra các lớp lambda vào thời gian biên dịch (các bản dựng JDK 8 ban đầu đã làm theo cách đó) trong trường hợp đó nó sẽ hoạt động trên bất kỳ phiên bản Java nào. (Oracle đã quyết định sử dụng invokeocate cho lambdas để chứng minh trong tương lai; có thể một ngày nào đó JVM sẽ có các hàm hạng nhất, do đó, inv invocate có thể được thay đổi để sử dụng chúng thay vì tạo một lớp cho mọi lambda, do đó cải thiện hiệu năng.) Retrolambda làm gì rằng nó xử lý tất cả các hướng dẫn inv invocate và thay thế chúng bằng các lớp ẩn danh; giống như những gì Java 8 thực hiện trong thời gian chạy khi một lệnh gọi lamdba được gọi lần đầu tiên.

Lặp đi lặp lại chú thích chỉ là cú pháp cú pháp. Chúng là mã byte tương thích với các phiên bản trước. Trong Java 7, bạn chỉ cần tự thực hiện các phương thức của trình trợ giúp (ví dụ getAnnotationsByType ) để ẩn chi tiết triển khai của một chú thích chứa có chứa các chú thích lặp đi lặp lại.

AFAIK, Chú thích loại chỉ tồn tại vào thời gian biên dịch, vì vậy chúng không nên yêu cầu thay đổi mã byte, do đó, chỉ cần thay đổi số phiên bản mã byte của các lớp được biên dịch Java 8 là đủ để chúng hoạt động trên Java 7.

Tên tham số của phương thức tồn tại trong mã byte với Java 7, do đó cũng tương thích. Bạn có thể có quyền truy cập vào chúng bằng cách đọc mã byte của phương thức và xem tên biến cục bộ trong thông tin gỡ lỗi của phương thức. Ví dụ, Spring Framework thực hiện chính xác điều đó để triển khai @PathVariable , vì vậy có thể có một phương thức thư viện mà bạn có thể gọi. Vì các phương thức giao diện trừu tượng không có phần thân phương thức, thông tin gỡ lỗi đó không tồn tại cho các phương thức giao diện trong Java 7 và AFAIK cũng không có trên Java 8.

Các tính năng mới khác chủ yếu là các API mới, cải tiến cho HotSpot và công cụ. Một số API mới có sẵn dưới dạng thư viện của bên thứ 3 (ví dụ ThreeTen-Backporthỗ trợ truyền phát ).

Tóm tắt, các phương thức mặc định yêu cầu các tính năng JVM mới nhưng các tính năng ngôn ngữ khác thì không. Nếu bạn muốn sử dụng chúng, bạn sẽ cần biên dịch mã trong Java 8 và sau đó chuyển đổi mã byte bằng Retrolambda sang định dạng Java 5/6/7. Tối thiểu phiên bản mã byte cần phải được thay đổi và javac không cho phép trình -source 1.8 -target 1.7điều khiển retrotranslator.


3
Trên thực tế các chú thích có thể được nhìn thấy thời gian chạy. stackoverflow.com/questions/22374612/ móc
Antimon

33

Theo như tôi biết thì không có thay đổi nào trong JDK 8 yêu cầu bổ sung mã byte mới. Một phần của thiết bị lambda đang được thực hiện bằng cách sử dụng invokeDynamic(đã tồn tại trong JDK 7). Vì vậy, từ quan điểm của tập lệnh JVM, không có gì làm cho cơ sở mã không tương thích. Mặc dù vậy, có rất nhiều cải tiến API liên quan và trình biên dịch có thể làm cho mã từ JDK 8 khó biên dịch / chạy theo các JDK trước đó (nhưng tôi chưa thử điều này).

Có lẽ các tài liệu tham khảo sau đây có thể giúp bằng cách nào đó làm phong phú thêm sự hiểu biết về cách những thay đổi liên quan đến lambda đang được áp dụng.

Những điều này giải thích chi tiết làm thế nào mọi thứ được thiết bị dưới mui xe. Có lẽ bạn có thể tìm thấy câu trả lời cho câu hỏi của bạn ở đó.


7
Không có mã byte mới, nhưng cấu trúc mới. Việc xác minh sẽ puke.
Jonathan S. Fisher

12
Một ví dụ điển hình là Giao diện. Bây giờ chúng có thể chứa các phương thức. Trình xác minh Java7 không được trang bị để xử lý việc này. Tất cả các mã byte cũ được sử dụng, nhưng theo một cách mới.
Jonathan S. Fisher

1
Tôi tự hỏi làm thế nào trình biên dịch scala với rất nhiều tính năng ngôn ngữ có thể đạt được một bản phát hành jvm mục tiêu thậm chí là jdk5.
Marinos An

1
@MarinosAn Ý bạn là gì? MI với những đặc điểm có chứa các phương pháp cụ thể, ví dụ class C extends A with B, được thực hiện với giao diện bình thường ABvà các lớp học đồng hành A$classB$class. lớp Cchỉ đơn giản là chuyển tiếp các phương thức đến các lớp đồng hành tĩnh. Các kiểu tự hoàn toàn không được thi hành, lambdas được dịch mã theo thời gian biên dịch sang các lớp bên trong trừu tượng, do đó là một new D with A with Bbiểu thức. Khớp mẫu là một loạt các cấu trúc if-other. Lợi nhuận phi địa phương? cơ chế thử bắt từ lambda. Còn gì không? (Thật thú vị, scalac của tôi nói 1.6 là mặc định)
Adowrath

1
Tất nhiên, các kiểu tự, v.v. được mã hóa trong các thuộc tính và chú thích lớp đặc biệt để scalac có thể sử dụng và thực thi các quy tắc khi sử dụng các lớp đã được biên dịch.
Adowrath


-5

Bạn có thể làm -source 1.7 -target 1.7sau đó nó sẽ biên dịch. Nhưng nó sẽ không biên dịch nếu bạn có các tính năng cụ thể của java 8 như lambdas


Câu hỏi đặt ra rõ ràng việc sử dụng các tính năng ngôn ngữ mới, vì vậy -source 1.7sẽ không bay.
toolforger
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.