คำสั่ง 'java' รวบรวมโปรแกรม Java หรือไม่


145

เว็บไซต์ส่วนใหญ่บนอินเทอร์เน็ตพูดว่า:

"ใช้javacคำสั่งเพื่อรวบรวม.javaไฟล์จากนั้นเรียกใช้โดยใช้javaคำสั่ง"

แต่วันนี้ฉันพยายามรันโปรแกรมจาวาโดยไม่ใช้javacและฉันได้ผลลัพธ์ที่แปลก

นี่คือเนื้อหาของไฟล์ที่เรียกว่าhello.java:

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

จากนั้นฉันก็วิ่ง:

$ javac hello.java

ซึ่งทำให้ฉันข้อผิดพลาดนี้:

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

แต่เมื่อฉันรันโดยไม่มีjavacคำสั่งมันจะทำงานโดยไม่มีข้อผิดพลาด

$ java hello.java
hello world

ที่ไม่javaคำสั่งนอกจากนี้ยังรวบรวมโปรแกรมได้หรือไม่ ถ้าใช่ทำไมเราต้องมีjavacคำสั่ง?

เวอร์ชันของ java ของฉันคือ:

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
คุณใช้เวอร์ชั่นไหน ฉันคิดว่าพวกเขาแนะนำ Java Console ใน Java 9 และนั่นอาจเป็นสิ่งที่คุณประสบ
Matthieu

6
คุณต้องจับคู่ชื่อคลาสกับชื่อไฟล์ - นั่นคือมาตรฐาน Java เพียงแค่เปลี่ยนชื่อไฟล์เพื่อMyclass.javaแล้วจากบรรทัดคำสั่งรวบรวมไว้เช่นนี้แล้วเรียกมันเช่นนี้javac Myclass.java java Myclass
unnsse

6
ใช่javacยังคงใช้ในการรวบรวมถ้าคุณไม่ต้องการปรับใช้รหัสแหล่งที่มาหรือคุณมีมากกว่าไฟล์เดียว ( เอกสารของjava: สำหรับตัวเลือกแหล่งที่มาของไฟล์ที่ใช้เท่านั้นที่จะเปิดตัวโปรแกรมที่มาไฟล์เดียว.)
user85421

@ แมทธิวเอาท์พุทของ "java -version" คือ: รุ่น openjdk "12.0.2" 2019-07-16 สภาพแวดล้อมรันไทม์ OpenJDK (สร้าง 12.0.2 + 10) เซิร์ฟเวอร์เซิร์ฟเวอร์ OpenJDK 64-bit VM (สร้าง 12.0.2 + 10 ผสม โหมด)
Milad

1
@Milad - สิ่งที่เกิดขึ้นคือสิ่งนี้ - javacรวบรวมแหล่งที่มาของ Java ลงในไบต์ที่แปลโดย JVM และjavaคำสั่งจะโหลดมันใน ClassLoader ของ JVM
แน่ใจ

คำตอบ:


188

ก่อนหน้า Java 11 เพื่อรันโค้ดของคุณคุณต้องคอมไพล์มันก่อนจากนั้นคุณสามารถรันมันได้ นี่คือตัวอย่าง:

javac test.java
java test

ตั้งแต่ Java 11 คุณยังสามารถทำjavac+ javaหรือคุณสามารถเรียกใช้javaด้วยตัวเองเพื่อรวบรวมและเรียกใช้รหัสของคุณโดยอัตโนมัติ โปรดทราบว่าจะไม่มีการ.classสร้างไฟล์ นี่คือตัวอย่าง:

java test.java

หากคุณเรียกใช้java -helpคุณจะเห็นประเพณีที่ได้รับอนุญาตต่างๆ นี่คือสิ่งที่ดูเหมือนในเครื่องของฉัน อันสุดท้ายคือสิ่งที่คุณพบ: java [options] <sourcefile> [args]ซึ่งจะ "รันโปรแกรมซอร์สไฟล์เดียว"

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

UPDATE:

ตามที่ชี้แจงโดย @BillK OP ก็ถามว่า:

ทำไมเราต้องการคำสั่ง javac

เหตุผลที่เราต้องการjavacคือการสร้าง.classไฟล์เพื่อให้โค้ดสามารถสร้างทดสอบแจกจ่ายใช้งานร่วมกันและอื่น ๆ ได้อย่างที่เป็นอยู่ทุกวันนี้ แรงจูงใจสำหรับJEP 330คือทำให้ง่ายขึ้นสำหรับ"ช่วงเริ่มต้นของการเรียนรู้ Java และเมื่อเขียนโปรแกรมอรรถประโยชน์ขนาดเล็ก"โดยไม่ต้องเปลี่ยนการใช้อื่น ๆ ที่มีอยู่



ขอบคุณ @CarlosHeuberger สำหรับรายละเอียดเพิ่มเติม ฉันทำการแก้ไขเล็กน้อยในคำตอบของฉันเพื่อสะท้อนว่ามันถูกนำมาใช้ใน Java 11
kaan

7
@Spikatrix ที่ Java 8 (พวกเขาลดลง1.ใน1.8ในรุ่นที่ใหม่กว่า)
Muru

1
คุณไม่ได้ตอบคำถามว่าทำไมเรายังต้องการ javac - ฉันคิดว่าจาวาทำงานบนไฟล์เดียวที่คุณให้ไว้และไฟล์ที่รวบรวมมาก่อนหน้านี้ ฉันเชื่อว่าคุณต้องรวบรวมไฟล์อื่น ๆ ทั้งหมดที่คุณต้องการใช้จากไฟล์ที่คุณโทร
Bill K

2
javacคำตอบนี้ไม่ได้อยู่ที่ว่าทำไมวิธีการใหม่นี้ไม่ได้ส่งผลให้เกิดข้อผิดพลาดชื่อชั้นชื่อไฟล์กับรายงานโดย
sebrockm

52

หากคุณกำลังเรียกใช้ Java 11มีคุณสมบัติใหม่ที่อนุญาตให้เรียกใช้ไฟล์ต้นฉบับได้ คอมไพเลอร์แหล่งที่มาเดียวมีความหลากหลายมากขึ้นในแง่ของชื่อคลาสกับชื่อไฟล์ดังนั้นนี่คือวิธีที่คุณสามารถรันได้ แต่ไม่สามารถคอมไพล์ได้สำเร็จ

หากคุณอยู่ในเวอร์ชันก่อนหน้าของ Javaดังนั้น hello.java ปัจจุบันของคุณจะไม่รวบรวมเนื่องจากข้อผิดพลาดในการคอมไพล์โดยเฉพาะรอบชื่อคลาส ดังนั้นจึงไม่มีทางที่จะเรียก java hello.java รวบรวมรหัสของคุณเพราะมันไม่ได้รวบรวม

ดูเหมือนว่าเป็นไปได้มากว่าคุณกำลังเรียกใช้โค้ดที่คอมไพล์ก่อนหน้านี้เมื่อรันคำสั่ง java


ขอขอบคุณรุ่น java คือ: รุ่น openjdk "12.0.2" 2019-07-16 สภาพแวดล้อมรันไทม์ OpenJDK (สร้าง 12.0.2 + 10) เซิร์ฟเวอร์ OpenJDK 64-Bit VM (สร้าง 12.0.2 + 10, โหมดผสม)
milad

5
ตรวจสอบการใช้โหมดซอร์สไฟล์เพื่อเปิดโปรแกรมซอร์สไฟล์รหัสเดี่ยว : "คอมไพเลอร์ไม่บังคับใช้ข้อ จำกัด เพิ่มเติมที่กำหนดไว้ในตอนท้ายของ JLS ?? 7.6 ว่าประเภทในแพ็คเกจที่มีชื่อควรมีอยู่ในไฟล์ที่ชื่อเป็น ประกอบด้วยชื่อประเภทตามด้วยนามสกุล. java "
user85421

2
Java scripting API และ Java Single-File Source-Code Program Launch ( JEP 330 ) เป็นสองสิ่งที่แยกจากกันอย่างสมบูรณ์และไม่เกี่ยวข้องกันโดยสิ้นเชิง
David Conrad

@DavidConrad อัพเดตคำฟุ่มเฟือยตาม ขอบคุณ
Evan

ขอบคุณอินพุต @TJCrowder แต่ฉันค่อนข้างแน่ใจว่าฉันตั้งใจจะเขียนมันตามที่เป็นอยู่ นอกจากนี้คำจำกัดความที่สองในลิงก์ของคุณ: หมายถึงสำส่อนรวมถึงสิ่งต่าง ๆ ที่หลากหลาย
Evan

6

basenameเพื่อที่จะตอบว่าทำไมข้อผิดพลาดนี้จะได้รับชื่อชั้นของไฟล์ต้องตรงกับของไฟล์

คุณมีสองตัวเลือกให้มีการทำงานรหัสนี้สำหรับแบบดั้งเดิมjavac; javaลำดับ:

  1. เปลี่ยนชื่อคลาสเป็นpublic class Helloหรือ

  2. เปลี่ยนชื่อไปhello.javamyclass.java

javaล่ามสำหรับ Java 11 ไม่ได้กำหนดความต้องการนี้ คลาสที่มีmainสามารถมีชื่อใด ๆ ตราบใดที่มันเป็นชั้นแรกในไฟล์ นี่เป็นจุดประสงค์หลักเพื่อลดขั้นตอนการเรียนรู้สำหรับผู้เริ่มต้นและอนุญาตให้ "การเขียนสคริปต์จาวา" กับ shebang (การอ้างอิง )


5

ใช่ แต่ไม่ใช่ในแบบที่คุณอาจหมายถึง

เมื่อคุณใช้javacคำสั่งเพื่อรวบรวมไฟล์. java เป็นไฟล์. class ผลลัพธ์จะเป็นสิ่งที่เรียกว่า bytecode Bytecode เป็นรหัสเครื่อง (คำสั่งพื้นฐาน) สำหรับ CPU เชิงทฤษฎีตามข้อกำหนดของ Java Virtual Machine

ข้อมูลจำเพาะเกี่ยวกับ CPU เสมือนนี้เป็นประเภทเฉลี่ยของประเภทของ CPU ที่ใช้กันทั่วไปในขณะที่ข้อมูลจำเพาะถูกเขียนขึ้น ด้วยเหตุนี้มันจึงอยู่ใกล้กับ CPU ประเภทต่าง ๆ มากมายทำให้ง่ายต่อการเรียกใช้ไฟล์ Java .class เดียวกันกับ CPU หลายประเภท

เมื่อ Java เปิดตัวครั้งแรกjavaคำสั่งจะอ่านไฟล์. class และตีความคำสั่ง bytecode ทีละครั้งจากนั้นจึงจับคู่คำสั่งนั้นกับคำสั่งเนทีฟที่เทียบเท่ากับสิ่งที่ CPU ใช้จริง ๆ สิ่งนี้ใช้ได้ แต่ก็ไม่เร็วโดยเฉพาะ เพื่อปรับปรุงการคอมไพล์ Just in Time (JIT) นี้ถูกเพิ่มใน Java Runtime

ด้วย JIT javaคำสั่งจะใช้ bytecode และคอมไพล์มันอีกครั้งไปยังคำสั่งพื้นฐานสำหรับ CPU ที่รันอยู่ Java runtimes ที่ทันสมัยมีแนวโน้มที่จะเริ่มตีความ bytecode ในขณะที่ JIT คอมไพล์ในพื้นหลังและสลับไปยังคำสั่งพื้นฐานที่คอมไพล์เมื่อมันพร้อมและจะทำการโพรไฟล์แอปพลิเคชั่นที่กำลังทำงานอยู่

แก้ไข (เพื่อเอาใจผู้มีสิทธิเลือกตั้งลง):

ดังนั้นในกรณีเฉพาะของคุณ (ขณะที่คุณใช้งาน JRE ใหม่กว่า v11) โค้ดจะถูกคอมไพล์ (อย่างน้อย) สองครั้ง

  1. เป็นไฟล์. java เดียวไปยัง bytecode
  2. ทางคอมไพเลอร์ JIT จะตีความรหัส bytecode (แต่สำหรับ helloWorld อาจไม่ได้เวลาที่จะเรียกใช้รหัสเนทีฟที่คอมไพล์แล้ว)

7
สิ่งนี้ไม่ตอบคำถาม
David Conrad

2
@DavidConrad แต่มันทำ! คำตอบของ "คำสั่ง 'java' รวบรวมโปรแกรม Java หรือไม่" เป็น "ใช่" ดังก้องสำหรับเหตุผล hardlib ให้ที่นี่: มันจะรวบรวมรหัสไบต์เพื่อคำแนะนำพื้นเมืองเพียงในเวลา (สำหรับโปรแกรมที่ไม่สำคัญกับการตั้งค่ามาตรฐาน)
Peter - Reinstate Monica

ตอนนี้จำเป็นต้องมีการรวบรวมหรือไม่? โค้ด Java byte ในอดีตสามารถตีความได้; การรวบรวม JIT เป็นทางเลือก
MSalters

JIT เปิดใช้งานตามค่าเริ่มต้นแล้ววันนี้ (เป็นเวลานานมาก) ตามที่แสดงโดยmixed-modeในผลลัพธ์เวอร์ชัน
hardillb
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.