Czy polecenie „java” kompiluje programy w języku Java?

145

Większość witryn internetowych podaje:

„użyj javacpolecenia, aby skompilować .javaplik. Następnie uruchom go za pomocą javapolecenia”

Ale dzisiaj próbowałem uruchomić program java bez javaci otrzymałem dziwny wynik.

Oto zawartość pliku o nazwie hello.java:

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

Potem pobiegłem:

$ javac hello.java

Co daje mi ten błąd:

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

Ale kiedy uruchamiam go bez javacpolecenia, wykonywał się bez żadnych błędów.

$ java hello.java
hello world

Czy javapolecenie również kompiluje program? Jeśli tak, po co nam javacpolecenie?

Wersja mojej javy to:

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
źródło
11
Jakiej wersji używasz? Myślę, że wprowadzili konsolę Java w Javie 9 i może właśnie tego doświadczyłeś.
Matthieu
6
Musisz dopasować nazwę klasy do nazwy pliku - to standard Java. Po prostu zmień nazwę pliku na, Myclass.javaa następnie z wiersza poleceń skompiluj go w ten sposób, javac Myclass.javaa następnie uruchom w ten sposób java Myclass.
unnsse
6
Tak, javacnadal używany do kompilacji, jeśli nie chcą wdrożyć kodu źródłowego, lub masz więcej niż jeden plik ( dokumentacja z java: dla opcji źródłowego pliku wyłącznie używany do uruchamiania jednego programu źródłowego pliku.)
user85421
@Matthieu wyjście „java -version” to: openjdk wersja „12.0.2” 2019-07-16 OpenJDK Runtime Environment (build 12.0.2 + 10) OpenJDK 64-bit Server VM (build 12.0.2 + 10, mieszane mode)
milad
1
@Milad - Co się dzieje, gdy jest to - javackompiluje źródło Java do interpretowanego kodu bajtowego specyficznego dla maszyny JVM, a javapolecenie ładuje je w module ClassLoader maszyny JVM.
unnsse

Odpowiedzi:

188

Przed wersją Java 11, aby uruchomić kod, musisz go najpierw skompilować, a następnie uruchomić. Oto przykład:

javac test.java
java test

Od wersji Java 11 nadal możesz robić javac+ javalub możesz uruchomić javasamodzielnie, aby skompilować i automatycznie uruchomić swój kod. Zauważ, że żaden .classplik nie zostanie wygenerowany. Oto przykład:

java test.java

Jeśli uciekniesz java -help, zobaczysz różne dozwolone zastosowania. Oto, jak to wygląda na moim komputerze. Ostatnim jest to, na co natrafiłeś: java [options] <sourcefile> [args]który „uruchomi program z pojedynczym plikiem źródłowym”.

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

AKTUALIZACJA:

Jak wskazał @BillK, OP zapytał również:

dlaczego potrzebujemy polecenia javac?

Powodem, dla którego potrzebujemy, javacjest tworzenie .classplików, aby kod mógł być tworzony, testowany, dystrybuowany, uruchamiany, współdzielony itp., Tak jak to jest obecnie. Motywacją dla JEP 330 było ułatwienie „wczesnych etapów nauki języka Java i pisania małych programów narzędziowych” bez zmiany jakichkolwiek innych istniejących zastosowań.

kaan
źródło
49
wprowadzone w Javie 11: Co nowego lub / i JEP 330: Uruchom programy z pojedynczym plikiem źródłowym
user85421
dzięki @CarlosHeuberger za dodatkowe szczegóły. Zrobiłem małą zmianę w mojej odpowiedzi, aby odzwierciedlić, że została wprowadzona w Javie 11.
kaan
7
@Spikatrix to Java 8 (one upuszczone 1.w 1.8w nowszych wydaniach)
Muru
1
Nie odpowiedziałeś na pytanie, dlaczego nadal potrzebujemy javaca - myślę, że java działa tylko na jednym dostarczonym pliku i wcześniej skompilowanych plikach. Uważam, że wszystkie inne pliki, których chcesz użyć, musisz skompilować z pliku, który dzwonisz.
Bill K
2
Ta odpowiedź nie wyjaśnia, dlaczego ta nowa metoda nie powoduje wystąpienia błędu nazwy pliku w porównaniu z nazwą klasy, zgodnie z raportem javac.
sebrockm
52

Jeśli używasz Java 11, dostępna jest nowa funkcja, która umożliwia wykonanie pojedynczego pliku źródłowego. Kompilator z jednym źródłem jest bardziej rozwiązły pod względem nazwy klasy w porównaniu z nazwą pliku, więc w ten sposób można uruchomić, ale nie można pomyślnie skompilować.

Jeśli korzystasz z poprzedniej wersji języka Java, bieżący plik hello.java nie kompiluje się z powodu błędów kompilacji, szczególnie wokół nazwy klasy. Więc nie ma absolutnie żadnego sposobu, aby wywołanie java hello.java skompilowało twój kod, ponieważ nie kompiluje się.

Wydaje się najbardziej prawdopodobne, że podczas wykonywania polecenia java uruchamiałeś jakiś wcześniej skompilowany kod.

Evan
źródło
dziękuję, wersja java to: wersja openjdk "12.0.2" 2019-07-16 Środowisko wykonawcze OpenJDK (wersja 12.0.2 + 10) 64-bitowa maszyna wirtualna serwera OpenJDK (wersja 12.0.2 + 10, tryb mieszany)
milad
5
check Używanie trybu pliku źródłowego do uruchamiania programów z pojedynczym plikiem kodu źródłowego : "Kompilator nie wymusza opcjonalnego ograniczenia zdefiniowanego na końcu JLS ?? 7.6, że typ w nazwanym pakiecie powinien istnieć w pliku o nazwie składa się z nazwy typu, po której następuje rozszerzenie .java. "
user85421
2
Java Scripting API i Java Single-File Source-Code Program Launch ( JEP 330 ) to dwie całkowicie oddzielne i całkowicie niepowiązane rzeczy.
David Conrad,
@DavidConrad, odpowiednio zaktualizowano słownictwo. Dzięki.
Evan,
Doceń wkład, @TJCrowder. Ale jestem całkiem pewien, że chciałem napisać to tak, jak jest. Druga definicja w linkach: rozwiązłość oznacza uwzględnianie szerokiego zakresu różnych rzeczy.
Evan,
6

Aby odpowiedzieć na pytanie, dlaczego podano ten błąd, nazwa klasy pliku musi być zgodna z nazwą pliku basename.

Masz dwie opcje, aby ten kod działał dla tradycyjnego javac; javasekwencja:

  1. Zmień nazwę klasy na public class Hellolub

  2. Zmień nazwę hello.javana myclass.java.

javaInterpreter Javy 11 nie nakłada tego wymogu. Klasa, która zawiera, mainmoże mieć dowolną nazwę, o ile jest to pierwsza klasa w pliku. Miało to głównie na celu ułatwienie procesu uczenia się początkującym i umożliwienie „tworzenia skryptów java” z użyciem shebang ( ref. ).

SS Anne
źródło
5

Tak, ale nie w sposób, jaki prawdopodobnie masz na myśli.

Kiedy używasz javacpolecenia do kompilowania pliku .java do pliku .class, wynik jest nazywany kodem bajtowym. Kod bajtowy to kod maszynowy (instrukcje natywne) teoretycznego procesora opartego na specyfikacji wirtualnej maszyny języka Java.

Ta specyfikacja wirtualnego procesora jest swego rodzaju średnią typami procesorów, które były powszechne w momencie pisania specyfikacji. Z tego powodu jest blisko wielu różnych typów procesorów, co ułatwia uruchamianie tych samych plików Java .class na wielu typach procesorów.

Kiedy Java została uruchomiona po raz pierwszy, javapolecenie odczytywało plik .class i interpretowało instrukcje kodu bajtowego pojedynczo, a następnie odwzorowywało je na równoważną instrukcję natywną dla dowolnego procesora, na którym faktycznie działał. To działało, ale nie było szczególnie szybkie. Aby to ulepszyć, do środowiska wykonawczego Java dodano kompilację Just in Time (JIT).

W przypadku JIT javapolecenie pobiera kod bajtowy i kompiluje go ponownie do natywnych instrukcji procesora, na którym działa. Nowoczesne środowiska wykonawcze Java zwykle rozpoczynają interpretację kodu bajtowego podczas kompilacji JIT w tle i przełączają się na skompilowane natywne instrukcje, gdy są gotowe, a także profilują działającą aplikację, a następnie ponownie kompilują kod bajtowy z inną optymalizacją, aby uzyskać najlepszą możliwą wydajność.

EDYTUJ (aby uspokoić słabych wyborców):

Więc w twoim konkretnym przypadku (ponieważ używasz JRE nowszego niż v11) kod jest kompilowany (co najmniej) dwukrotnie

  1. Jako pojedynczy plik .java do kodu bajtowego
  2. Za pośrednictwem kompilatora JIT, który interpretuje kod bajtowy (chociaż w przypadku helloWorld może nie mieć czasu na uruchomienie skompilowanego kodu natywnego)
hardillb
źródło
7
To nie odpowiada na pytanie.
David Conrad
2
@DavidConrad Ale tak jest! Odpowiedź na pytanie „Czy polecenie 'java' kompiluje programy w języku Java?” jest zdecydowanym „tak” z powodów, które podaje tutaj hardlib: będzie kompilować kod bajtowy do natywnych instrukcji dokładnie na czas (dla nietrywialnych programów, ze standardowymi ustawieniami).
Peter - Przywróć Monikę
Czy kompilacja jest teraz obowiązkowa? Historycznie rzecz biorąc, kod bajtowy Java mógł być interpretowany; Kompilacja JIT była opcjonalna.
MSalters
JIT jest obecnie domyślnie włączony (przez bardzo długi czas), jak pokazuje mixed-modewynik wersji
hardillb