Lệnh 'java' có biên dịch các chương trình Java không?


145

Hầu hết các trang web trên internet đều nói:

"sử dụng javaclệnh để biên dịch một .javatập tin. Sau đó chạy nó bằng javalệnh"

Nhưng hôm nay tôi đã cố gắng chạy một chương trình java mà không có javacvà tôi đã nhận được một kết quả lạ.

Dưới đây là nội dung của một tệp có tên hello.java:

public class Myclass {
 public static void main(String[] args){
    System.out.println("hello world");
  }
}

Rồi tôi chạy:

$ javac hello.java

Điều này cho tôi lỗi này:

hello.java:1: error: class Myclass is public, should be declared in a file named Myclass.java
public class Myclass {
       ^
1 error

Nhưng khi tôi chạy nó mà không có javaclệnh, nó đã thực thi mà không có bất kỳ lỗi nào.

$ java hello.java
hello world

Liệu javalệnh cũng biên dịch chương trình? Nếu có, tại sao chúng ta cần javaclệnh?

Phiên bản java của tôi là:

openjdk version "12.0.2" 2019-07-16
OpenJDK Runtime Environment (build 12.0.2+10)
OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode)

11
Phiên bản bạn đang sử dụng? Tôi nghĩ rằng họ đã giới thiệu Bảng điều khiển Java trong Java 9 và đó có thể là những gì bạn đã trải nghiệm.
Matthieu

6
Bạn cần khớp tên lớp với tên tệp của nó - đó là tiêu chuẩn Java. Chỉ cần thay đổi tên tệp thành Myclass.javavà sau đó từ dòng lệnh biên dịch nó như thế này javac Myclass.javavà sau đó chạy nó như thế này java Myclass.
mở ra

6
có, javacvẫn được sử dụng để biên dịch nếu bạn không muốn triển khai mã nguồn hoặc bạn có nhiều hơn một tệp ( tài liệu về javatùy chọn tệp nguồn: Chỉ được sử dụng để khởi chạy một chương trình tệp nguồn duy nhất.)
user85421

@Matthieu đầu ra của "java -version" là: phiên bản openjdk "12.0.2" 2019-07-16 Môi trường thời gian chạy OpenJDK (bản dựng 12.0.2 + 10) VM máy chủ 64 bit OpenJDK (bản dựng 12.0.2 + 10, hỗn hợp chế độ)
milad

1
@Milad - Điều gì xảy ra là thế này - javacbiên dịch nguồn Java thành mã byte được giải thích cụ thể của JVM và javalệnh sẽ tải nó bên trong ClassLoader của JVM.
mở ra

Câu trả lời:


188

Trước Java 11, để chạy mã của bạn, trước tiên bạn phải biên dịch mã, sau đó bạn có thể chạy mã đó. Đây là một ví dụ:

javac test.java
java test

Kể từ Java 11, bạn vẫn có thể thực hiện javac+ javahoặc bạn có thể tự chạy javađể biên dịch và tự động chạy mã của mình. Lưu ý rằng không có .classtập tin sẽ được tạo ra. Đây là một ví dụ:

java test.java

Nếu bạn chạy java -help, bạn sẽ thấy các cách sử dụng được phép khác nhau. Đây là những gì nó trông giống như trên máy tính của tôi. Cái cuối cùng là cái bạn đã chạy vào: java [options] <sourcefile> [args]cái này sẽ "thực thi một chương trình tệp nguồn duy nhất".

$ java -help
Usage: java [options] <mainclass> [args...]
           (to execute a class)
   or  java [options] -jar <jarfile> [args...]
           (to execute a jar file)
   or  java [options] -m <module>[/<mainclass>] [args...]
       java [options] --module <module>[/<mainclass>] [args...]
           (to execute the main class in a module)
   or  java [options] <sourcefile> [args]
           (to execute a single source-file program)

CẬP NHẬT:

Như @BillK đã chỉ ra, OP cũng đã hỏi:

Tại sao chúng ta cần lệnh javac?

Lý do chúng ta cần javaclà tạo .classcác tệp để mã có thể được tạo, kiểm tra, phân phối, chạy, chia sẻ, v.v. như ngày nay. Động lực của JEP 330 là giúp "giai đoạn đầu học Java và khi viết các chương trình tiện ích nhỏ" dễ dàng hơn mà không thay đổi bất kỳ cách sử dụng hiện có nào khác.


49

cảm ơn @CarlosHeuberger để biết thêm chi tiết. Tôi đã thực hiện một chỉnh sửa nhỏ trong câu trả lời của mình để phản ánh rằng nó đã được giới thiệu trong Java 11.
kaan

7
@Spikatrix đó là Java 8 (Họ bỏ 1.trong 1.8trong phiên bản mới hơn)
muru

1
Bạn đã không trả lời câu hỏi tại sao chúng ta vẫn cần javac - Tôi nghĩ java chỉ hoạt động trên một tệp bạn cung cấp và các tệp được biên dịch trước đó. Tôi tin rằng bạn phải biên dịch tất cả các tệp khác mà bạn muốn sử dụng từ tệp bạn gọi.
Bill K

2
Câu trả lời này không giải quyết tại sao phương thức mới này không dẫn đến tên tệp so với lỗi tên lớp như được báo cáo bởi javac.
sebrockm

52

Nếu bạn đang chạy Java 11, có một tính năng mới cho phép thực thi tệp nguồn đơn. Trình biên dịch mã nguồn đơn lẻ hơn về mặt tên lớp so với tên tệp, vì vậy đó là cách bạn có thể chạy nhưng không biên dịch thành công.

Nếu bạn đang sử dụng phiên bản Java trước, thì hello.java hiện tại của bạn không biên dịch được, do lỗi biên dịch, cụ thể là xung quanh tên lớp. Vì vậy, hoàn toàn không có cách nào gọi java hello.java biên dịch mã của bạn, bởi vì nó không biên dịch.

Có vẻ như rất có thể bạn đang chạy một số mã được biên dịch trước đó khi thực hiện lệnh java.


cảm ơn bạn, phiên bản java là: phiên bản openjdk "12.0.2" 2019-07-16 OpenJDK Runtime Môi trường (bản dựng 12.0.2 + 10) Máy chủ OpenJDK 64-Bit (bản dựng 12.0.2 + 10, chế độ hỗn hợp)
milad

5
kiểm tra Sử dụng Chế độ tệp nguồn để khởi chạy các chương trình mã nguồn tệp đơn : "Trình biên dịch không thi hành hạn chế tùy chọn được xác định ở cuối JLS ?? 7.6, rằng một loại trong gói có tên phải tồn tại trong tệp có tên là bao gồm từ tên loại theo sau là phần mở rộng .java. "
dùng85421

2
API kịch bản Java và Khởi chạy chương trình mã nguồn tệp đơn Java ( JEP 330 ) là hai thứ hoàn toàn riêng biệt và hoàn toàn không liên quan.
David Conrad

@DavidConrad, cập nhật verbiage cho phù hợp. Cảm ơn.
Evan

Đánh giá cao đầu vào, @TJCrowder. Nhưng, tôi khá chắc chắn rằng tôi có ý định viết nó như vậy. Ngoài ra, định nghĩa thứ hai trong các liên kết của bạn: Phương tiện lăng nhăng bao gồm một loạt các thứ khác nhau.
Evan

6

Để trả lời tại sao lỗi này được đưa ra, tên lớp cho tệp phải khớp với tệp basename.

Bạn có hai tùy chọn để mã này hoạt động cho truyền thống javac; javasự nối tiếp:

  1. Đổi tên lớp thành public class Hellohoặc

  2. Đổi tên hello.javathành myclass.java.

Trình javathông dịch cho Java 11 không áp đặt yêu cầu này. Lớp chứa maincó thể có bất kỳ tên nào, miễn là lớp đầu tiên trong tệp. Điều này chủ yếu nhằm giảm bớt quá trình học tập cho người mới bắt đầu và cho phép "java scripting" với shebang ( ref. ).


5

Có, nhưng không phải theo cách bạn có thể có nghĩa.

Khi bạn sử dụng javaclệnh để biên dịch tệp .java thành tệp. Class, đầu ra là một cái gì đó được gọi là mã byte. Bytecode là mã máy (hướng dẫn riêng) cho CPU lý thuyết dựa trên đặc tả Máy ảo Java.

Đặc tả CPU ảo này là loại trung bình của các loại CPU phổ biến tại thời điểm thông số kỹ thuật được viết. Do đó, nó gần với nhiều loại CPU khác nhau, giúp chạy các tệp Java. Class dễ dàng hơn trên nhiều loại CPU.

Khi Java lần đầu tiên được khởi chạy, javalệnh sẽ đọc tệp. Class và giải thích các lệnh của mã byte một lần và sau đó ánh xạ chúng tới lệnh gốc tương đương cho CPU mà nó thực sự đang chạy. Điều này làm việc nhưng không đặc biệt nhanh. Để cải thiện việc biên dịch Just in Time (JIT) này đã được thêm vào Java Runtime.

Với JIT, javalệnh sẽ lấy mã byte và biên dịch lại thành các lệnh gốc cho CPU mà nó đang chạy. Các thời gian chạy Java hiện đại có xu hướng bắt đầu diễn giải mã byte trong khi JIT biên dịch trong nền và chuyển sang các hướng dẫn gốc được biên dịch khi nó sẵn sàng và cũng sẽ cấu hình lại ứng dụng đang chạy và sau đó biên dịch lại mã byte bằng cách tối ưu hóa khác nhau để có hiệu suất tốt nhất có thể.

EDIT (để xoa dịu các cử tri xuống):

Vì vậy, trong trường hợp cụ thể của bạn (vì bạn đang chạy JRE mới hơn v11), mã được biên dịch (ít nhất) hai lần

  1. Là một tệp .java thành mã byte
  2. Thông qua trình biên dịch JIT vì nó diễn giải mã byte (mặc dù đối với helloWorld, nó thực sự có thể không có thời gian để chạy bất kỳ mã gốc được biên dịch nào)

7
Điều này không trả lời câu hỏi.
David Conrad

2
@DavidConrad Nhưng không! Câu trả lời cho "Lệnh 'java' có biên dịch các chương trình Java không?" là một tiếng "có" vang dội vì những lý do hardlib đưa ra ở đây: nó sẽ biên dịch mã byte thành các lệnh gốc ngay lập tức (đối với các chương trình không tầm thường, với các cài đặt tiêu chuẩn).
Peter - Tái lập Monica

Là biên dịch bây giờ là bắt buộc? Mã byte Java trong lịch sử có thể được giải thích; Biên soạn JIT là tùy chọn.
MSalters

JIT được bật theo mặc định những ngày này (trong một thời gian rất dài), như được hiển thị bởi đầu ra mixed-modetrong phiên bản
hardillb
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.