¿El comando ''java'' compila programas Java?
javac (5)
La mayoría de los sitios web en internet dicen:
"use el comando
javac
para compilar un archivo.java
. Luego ejecútelo usando el comandojava
"
Pero hoy intenté ejecutar un programa java sin
javac
y obtuve un resultado extraño.
Aquí están los contenidos de un archivo llamado
hello.java
:
public class Myclass {
public static void main(String[] args){
System.out.println("hello world");
}
}
Entonces corrí:
$ javac hello.java
Lo que me da este error:
hello.java:1: error: class Myclass is public, should be declared in a file named Myclass.java
public class Myclass {
^
1 error
Pero cuando lo ejecuto sin el comando
javac
, se ejecutó sin ningún error.
$ java hello.java
hello world
¿El comando
java
también compila el programa?
En caso afirmativo, ¿por qué necesitamos el comando
javac
?
La versión de mi java es:
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)
Antes de Java 11, para ejecutar su código primero debe compilarlo, luego puede ejecutarlo. Aquí hay un ejemplo:
javac test.java
java test
Desde Java 11, aún puede hacer
javac
+
java
, o puede ejecutar
java
solo para compilar y ejecutar automáticamente su código.
Tenga en cuenta que no se generará ningún archivo
.class
.
Aquí hay un ejemplo:
java test.java
Si ejecuta
java -help
, verá los diversos usos permitidos.
Así es como se ve en mi máquina.
El último es con el que se encontró:
java [options] <sourcefile> [args]
que "ejecutará un único programa de archivo fuente".
$ 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)
ACTUALIZAR:
Como señaló @BillK, OP también preguntó:
¿Por qué necesitamos el comando javac?
La razón por la que necesitamos
javac
es crear archivos
.class
para que el código se pueda crear, probar, distribuir, ejecutar, compartir, etc., como es hoy.
La motivación para
JEP 330
fue facilitar las
"primeras etapas de aprendizaje de Java y al escribir pequeños programas de utilidad"
sin cambiar ningún otro uso existente.
Esta característica proporciona la capacidad de ejecutar un código fuente de un solo archivo de Java directamente sin ninguna compilación, evitando los tediosos pasos que anteriormente implicaban ejecutar solo un simple programa hello world.
Java 11+ Launch Single-File Source-Code Programs
Por qué necesita esto Si recuerda los viejos tiempos justo antes de Java SE 11 (JDK 11), supongamos que tiene un archivo fuente HelloUniverse.java que contiene una definición de clase y un método principal estático que se imprime como una sola línea de texto en el terminal como el siguiente:
public class HelloUniverse{
public static void main(String[] args) {
System.out.println("Hello InfoQ Universe");
}
}
Normalmente, para ejecutar esta clase, primero, necesitaría compilarla usando un compilador Java (javac), lo que daría como resultado un archivo HelloUniverse.class:
$ javac HelloUniverse.java
Then you would use a java virtual machine (interpreter) command to run the resulting class file:
$ java HelloUniverse
Hello InfoQ Universe
Esto inicia la JVM, carga la clase y ejecuta el código.
Pero, ¿qué pasa si quieres probar rápidamente un fragmento de código y quieres experimentar? Esos dos pasos en el proceso pueden parecer un poco pesados. En Java SE 11, tiene la opción de iniciar un único archivo de código fuente directamente, sin compilación intermedia.
Para responder por qué se da este error, el nombre de la clase para el archivo debe coincidir con el
basename
del archivo.
Tiene dos opciones para que este código funcione para el
javac
tradicional;
secuencia de
java
:
-
Cambie el nombre de la clase a
public class Hello
o -
Cambie el nombre de
hello.java
amyclass.java
.
El intérprete de Java para Java 11 no impone este requisito.
La clase que contiene
main
puede tener cualquier nombre, siempre que sea la primera clase en el archivo.
Esto estaba destinado principalmente a facilitar el proceso de aprendizaje para principiantes, y para permitir "java scripting" con el shebang (
ref.
).
Sí, pero no de la manera que probablemente quieras decir.
Cuando usa el comando
javac
para compilar un archivo .java en un archivo .class, la salida es algo llamado bytecode.
Bytecode es un código de máquina (instrucciones nativas) para una CPU teórica basada en la especificación de Java Virtual Machine.
Esta especificación de CPU virtual es una especie de promedio de tipos de CPU que eran comunes en el momento en que se escribió la especificación. Debido a esto, está cerca de muchos tipos diferentes de CPU, lo que facilita la ejecución de los mismos archivos Java .class en múltiples tipos de CPU.
Cuando se lanzó Java por primera vez, el comando
java
leería el archivo .class e interpretaría las instrucciones de bytecode de una en una y luego las correlacionaría con la instrucción nativa equivalente para la CPU en la que se estaba ejecutando.
Esto funcionó pero no fue particularmente rápido.
Para mejorar esta compilación Just in Time (JIT) se agregó a Java Runtime.
Con JIT, el comando
java
toma el bytecode y lo vuelve a compilar con las instrucciones nativas para la CPU en la que se está ejecutando.
Los tiempos de ejecución modernos de Java tienden a comenzar a interpretar el código de bytes mientras compila JIT en segundo plano y cambiar a las instrucciones nativas compiladas cuando está listo y también perfilará la aplicación en ejecución y luego volverá a compilar el código de bytes con una optimización diferente para obtener el mejor rendimiento posible.
EDITAR (para apaciguar a los votantes caídos):
Entonces, en su caso específico (ya que está ejecutando un JRE más nuevo que v11), el código se compila (al menos) dos veces
- Como un único archivo .java para bytecode
- A través del compilador JIT, ya que interpreta el código de bytes (aunque para helloWorld podría no tener tiempo para ejecutar ninguno de los códigos nativos compilados)
Si está ejecutando Java 11, hay una nueva característica que permite la ejecución de un único archivo fuente. El compilador de fuente única es más promiscuo en términos de nombre de clase versus nombre de archivo, por lo que así es como puede ejecutar pero no compilar correctamente.
Si está en una versión anterior de Java, entonces su hello.java actual no se compila, debido a errores de compilación, específicamente alrededor del nombre de la clase. Entonces, no hay absolutamente ninguna manera de que llamar a java hello.java compile su código, porque no se compila.
Parece muy probable que estuviera ejecutando algún código compilado previamente al ejecutar el comando java.