Apakah perintah 'java' mengkompilasi program Java?

146

Sebagian besar situs web di internet mengatakan:

"gunakan javacperintah untuk mengkompilasi .javafile. Kemudian jalankan dengan menggunakan javaperintah"

Tapi hari ini saya mencoba menjalankan program java tanpa javacdan saya mendapat hasil yang aneh.

Berikut adalah isi file yang disebut hello.java:

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

Lalu aku berlari:

$ javac hello.java

Yang memberi saya kesalahan ini:

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

Tetapi ketika saya menjalankannya tanpa javacperintah, itu dieksekusi tanpa kesalahan.

$ java hello.java
hello world

Apakah javaperintah juga mengkompilasi program? Jika ya, mengapa kita membutuhkan javacperintah?

Versi java saya adalah:

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)
milad
sumber
11
Versi mana yang Anda gunakan? Saya pikir mereka memperkenalkan Java Console di Java 9, dan itu mungkin yang Anda alami.
Matthieu
6
Anda harus mencocokkan nama kelas dengan nama file - itulah standar Java. Ubah saja nama file ke Myclass.javadan kemudian dari baris perintah kompilasi seperti ini javac Myclass.javadan kemudian jalankan seperti ini java Myclass.
lepaskan
6
ya, javacmasih digunakan untuk mengkompilasi jika Anda tidak ingin menyebarkan kode sumber, atau Anda memiliki lebih dari satu file ( dokumentasi dari java: untuk opsi sumber-berkas Hanya digunakan untuk meluncurkan program sumber-file tunggal.)
user85421
@Matthieu output dari "java -version" adalah: versi openjdk "12.0.2" 2019-07-16 OpenJDK Runtime Environment (build 12.0.2 + 10) OpenJDK Server 64-Bit Server VM (build 12.0.2 + 10, dicampur mode)
milad
1
@Milad - Apa yang terjadi adalah ini - javacmengkompilasi sumber Java ke dalam bytecode spesifik JVM yang ditafsirkan dan javaperintah memuatnya di dalam ClassLoader JVM.
unnsse

Jawaban:

189

Sebelum ke Java 11, untuk menjalankan kode Anda, Anda harus terlebih dahulu mengkompilasinya, kemudian Anda dapat menjalankannya. Ini sebuah contoh:

javac test.java
java test

Sejak Java 11, Anda masih dapat melakukan javac+ java, atau Anda dapat menjalankannya javasendiri untuk mengkompilasi dan menjalankan otomatis kode Anda. Perhatikan bahwa tidak ada .classfile yang akan dihasilkan. Ini sebuah contoh:

java test.java

Jika Anda menjalankan java -help, Anda akan melihat berbagai penggunaan yang diizinkan. Begini tampilannya di komputer saya. Yang terakhir adalah apa yang Anda temui: java [options] <sourcefile> [args]yang akan "mengeksekusi program file sumber tunggal".

$ 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)

MEMPERBARUI:

Seperti yang ditunjukkan oleh @BillK, OP juga bertanya:

mengapa kita membutuhkan perintah javac?

Alasan yang kita butuhkan javacadalah membuat .classfile sehingga kode dapat dibuat, diuji, didistribusikan, dijalankan, dibagikan, dll. Seperti sekarang ini. Motivasi untuk JEP 330 adalah untuk membuatnya lebih mudah untuk "tahap awal belajar Java, dan ketika menulis program utilitas kecil" tanpa mengubah kegunaan lain yang ada.

kaan
sumber
49
diperkenalkan di Java 11: Apa yang Baru atau / dan JEP 330: Luncurkan Program Kode-Sumber File Tunggal
user85421
terima kasih @CarlosHeuberger untuk detail tambahan. Saya menyunting kecil jawaban saya untuk mencerminkan bahwa itu diperkenalkan di Jawa 11.
kaan
7
@Spikatrix itu Java 8 (Mereka menjatuhkan 1.di 1.8dalam rilis yang lebih baru)
Muru
1
Anda tidak menjawab pertanyaan mengapa kita masih membutuhkan javac - saya pikir java hanya beroperasi pada satu file yang Anda berikan dan file yang sebelumnya dikompilasi. Saya yakin Anda harus mengkompilasi semua file lain yang ingin Anda gunakan dari file yang Anda panggil.
Bill K
2
Jawaban ini tidak membahas mengapa metode baru ini tidak menghasilkan kesalahan nama file vs nama kelas seperti yang dilaporkan oleh javac.
sebrockm
52

Jika Anda menjalankan Java 11, ada fitur baru yang memungkinkan eksekusi file sumber tunggal. Kompiler sumber tunggal lebih bebas dalam hal nama kelas dibandingkan nama file, sehingga Anda dapat menjalankannya tetapi tidak berhasil mengompilasi.

Jika Anda menggunakan versi Java sebelumnya, maka hello.java Anda saat ini tidak dapat dikompilasi, karena kesalahan kompilasi, khususnya di sekitar nama kelas. Jadi sama sekali tidak ada cara memanggil java hello.java mengkompilasi kode Anda, karena itu tidak mengkompilasi.

Tampaknya kemungkinan besar Anda menjalankan beberapa kode yang dikompilasi sebelumnya ketika menjalankan perintah java.

Evan
sumber
terima kasih, versi java adalah: versi openjdk "12.0.2" 2019-07-16 OpenJDK Runtime Environment (build 12.0.2 + 10) OpenJDK 64-Bit Server VM (build 12.0.2 + 10, mode campuran)
milad
5
centang Menggunakan Mode Sumber-File untuk Meluncurkan Program Kode-Sumber File Tunggal : "Kompiler tidak menerapkan pembatasan opsional yang ditentukan pada akhir JLS ?? 7.6, bahwa jenis dalam paket bernama harus ada dalam file yang namanya adalah terdiri dari nama jenis diikuti oleh ekstensi .java. "
user85421
2
Java scripting API dan Java Single-File Source-Code Program Launch ( JEP 330 ) adalah dua hal yang benar-benar terpisah dan sama sekali tidak terkait.
David Conrad
@ Davidvidon, diperbarui kata yang sesuai. Terima kasih.
Evan
Hargai input, @TJCrowder. Tapi, saya cukup yakin saya bermaksud menulis apa adanya. Juga, definisi kedua di tautan Anda: Promiscuous berarti memasukkan berbagai hal.
Evan
6

Untuk menjawab mengapa kesalahan ini diberikan, nama kelas untuk file tersebut harus cocok dengan file tersebut basename.

Anda memiliki dua opsi untuk membuat kode ini berfungsi untuk tradisional javac; javaurutan:

  1. Ubah nama kelas menjadi public class Helloatau

  2. Ganti nama hello.javamenjadi myclass.java.

The javainterpreter untuk Java 11 tidak memaksakan persyaratan ini. Kelas yang berisi maindapat memiliki nama apa saja, asalkan itu adalah kelas pertama dalam file. Ini terutama dimaksudkan untuk memudahkan proses pembelajaran bagi pemula, dan untuk memungkinkan "scripting java" dengan shebang ( ref. ).

SS Anne
sumber
5

Ya, tapi tidak dengan cara yang Anda maksudkan.

Ketika Anda menggunakan javacperintah untuk mengkompilasi file .java ke file .class, outputnya adalah sesuatu yang disebut bytecode. Bytecode adalah kode mesin (instruksi asli) untuk CPU teoretis berdasarkan spesifikasi Java Virtual Machine.

Spesifikasi CPU virtual ini adalah jenis rata-rata jenis CPU yang umum pada saat spesifikasi ditulis. Karena ini, ia dekat dengan banyak jenis CPU yang berbeda sehingga memudahkan untuk menjalankan file Java .class yang sama pada beberapa jenis CPU.

Ketika Java pertama kali diluncurkan, javaperintah akan membaca file .class dan menginterpretasikan instruksi bytecode satu per satu dan kemudian memetakannya ke instruksi asli yang setara untuk CPU yang sebenarnya dijalankan. Ini berhasil tetapi tidak terlalu cepat. Untuk meningkatkan kompilasi Just in Time (JIT) ini telah ditambahkan ke Java Runtime.

Dengan JIT, javaperintah tersebut mengambil bytecode dan mengkompilasinya kembali ke instruksi asli untuk CPU yang digunakan. Runtime Java modern cenderung mulai menafsirkan bytecode sementara JIT mengkompilasi di latar belakang dan beralih ke instruksi asli yang dikompilasi ketika sudah siap dan juga akan profil aplikasi yang berjalan dan kemudian mengkompilasi ulang bytecode lagi dengan optimasi yang berbeda untuk mendapatkan kinerja terbaik.

EDIT (untuk menenangkan pemilih yang turun):

Jadi dalam kasus spesifik Anda (saat Anda menjalankan JRE lebih baru dari v11) kode dikompilasi (setidaknya) dua kali

  1. Sebagai file .java tunggal untuk bytecode
  2. Melalui kompiler JIT saat menginterpretasikan bytecode (meskipun untuk helloWorld mungkin tidak mendapatkan waktu untuk menjalankan kode asli yang dikompilasi)
hardillb
sumber
7
Ini tidak menjawab pertanyaan.
David Conrad
2
@ Davidvidon Tapi itu! Jawaban untuk "Apakah perintah 'java' mengkompilasi program Java?" adalah "ya" dengan alasan yang diberikan hardlib di sini: itu akan mengkompilasi kode byte ke instruksi asli tepat waktu (untuk program non-sepele, dengan pengaturan standar).
Peter - Reinstate Monica
Apakah kompilasi sekarang wajib? Secara historis kode byte Java dapat diartikan; Kompilasi JIT adalah opsional.
MSalters
JIT aktif secara default hari ini (untuk waktu yang sangat lama), seperti yang ditunjukkan oleh mixed-modedalam versi keluaran
hardillb