Uso de javac y java rev 1.2

Antes de usar javac ó java tener en cuenta :
– Si se usa Windows7 abrir las ventanas de comandos con permisos de Administrador.
– En el sistema de archivos de los SO Windows el separador de directorios es el backslash \ y en los SO tipo Linux es el forward slash /.
– Colocar en la variable de entorno la ruta del JRE (que esta dentro del directorio Java, no del JDK).
– Con las opciones -d y -classpath el delimitador o separador de paths en los SO Windows es ; y en los SO tipo Linux es :.
– Cuando se use un path absoluto, en los SO Windows la raíz de un path puede ser C:\, D:\, E:\ u otra letra de unidad y en los SO tipo Linux es /.

Compilado con javac
El comando javac se usa para invocar al compilador de Java.
Enfocaré en el uso de las opciones -classpath y -d.

 javac [opciones] [archivos fuente] 

Además existen otras opciones llamadas @argfiles.
Tanto [opciones] y [archivos fuente] son opcionales pero permiten múltiples entradas.

Los ejemplos con los que se comenzará se realizarán sobre un SO tipo Linux y por lo tanto se usará el separador de directorios fordward slash “/” y el separador de paths “:”. Al final se tiene 2 ejemplos que se realizan sobre SO Windows para notar la diferencia en cuanto al uso de los separadores de directorios y los separadores de paths.
Las sgtes entradas son legales :

javac -help
javac -classpath com:. -g Foo.java Bar.java

La primera invocación no compila ningún archivo pero muestra un sumario de las opciones del comando.
La segunda invocación le pasa al compilador dos opciones (-classes con su argumento com:. y -g) y le pasa al compilador dos archivos Foo.java y Bar.java . Siempre que especifiques varias opciones y/o archivos se deben separar por espacios.

Compilado con -d
Por defecto el compilador pone el archivo class en el mismo directorio donde esta su source code. Esto esta bien para proyectos pequeños , pero no para proyectos grandes en los que se necesita separar los source codes de los class. La opcion -d le dice al compilador en que directorio colocar los archivos class generados.

Para comprobar el uso de los comandos de java y javac se trabajara con la sgte estructura de directorios :
myProject
|
|–source
| |
| |– MyClass.java
|
|– classes
|
|–

public class MyClass {
	public MyClass (){
		System.out.println("Desde MyClass ");
	}

	public void mensaje(String nombre){
		System.out.println("Hola "+nombre);
	}

	public static void main(String args[]){
		Compilando cpd = new Compilando();
		cpd.mensaje("Steve");
	}
}

El sgte comando ejecutado desde el directorio MyProject compilará MyClass.java y colocara el MyClass.class resultante en el directorio classes (tener en cuenta que MyClass.java no tiene alguna sentencia de paquete).

cd myProject
javac -d classes source/MyClass.java

Ahora suponiendo que tenemos la sgte estructura de directorios con esta otra clase Java:

package com.wickedlysmart;

public class MyClass {
	public MyClass (){
		System.out.println("Desde compilando");
	}

	public void mensaje(String nombre){
		System.out.println("Hola "+nombre);
	}

	public static void main(String args[]){
		Compilando cpd = new Compilando();
		cpd.mensaje("Jorge");
	}
}

Resultado de compilar MyClass.java con javac
myProject
|
|–source
| |
| |–com
| |
| |–wickedlysmart
| |
| |–MyClass.java
|
|–classes
| |
| |–com
| |
| |–wickedlysmart
| |
| |– (MyClass.class va aquí)

Si estas en el directorio source y deseas compilar MyClass.java para colocar el MyClass.class resultante en classes/com/wickedlysmart lo debes hacer con el sgte comando :
javac -d ../classes com/wickedlysmart/MyClass.java

Este comando es leido asi : Para establecer el directorio de destino cd hacia el directorio myProject, luego ir al directorio classes, el cual quedara como el directorio destino.

Luego compila el archivo MyClass.java. Finalmento coloca el archivo resultante MyClass.class en la estructura de directorio que coincide con su paquete, en este caso : classes/com/wickedlysmart. Debido a que MyClass.java esta en un paquete, el compilador sabe que debe poner el el archivo .class resultante en el directorio classes/com/wickedlysmart.

Algo muy util que hace este comando javac es que le ayuda a crear la estructura de directorios cuando la necesite.
Suponer que se tiene la ultima clase MyClass.java con esta otra estructura de directorios :

myProject
|
|–source
| |
| |–com
| |
| |–wickedlysmart
| |
| |–MyClass.java
|
|–classes
| |
Al ejecutar el mismo comando de la ultima vez :

javac -d ../classes com/wickedlysmart/MyClass.java

Se obtiene misma estructura de directorios de la ultima vez.
En este caso el compilador crea dos directorios com y com/wickedlysmart para poner el archivo MyClass.class en el directorio correcto de acuerdo con la estructura del paquete (com/wickedlysmart/) los cuales son construidos dentro del directorio …/classes existente.

Se debe tener en cuenta que si se usa -d con un directorio de destino que no existe, se obtendra un error de compilacion. Si en el ejemplo el directorio classes no existe, el compilador mostrara algo como esto :

java:5: error while writing MyClass: classes/MyClass.class (No
such file or directory)

Lanzando aplicaciones con Java

El comando java se usa para invocar a la JVM. Para el examen se necesitara saber las opciones -classpath ( ó cp) y -D.
La estructura del comando es la sgte :

java [options] class [args]

Las partes [options] y [args] son opcionales y ambas pueden tener multiples valores. Solo debes especificar un archivo class para ejecutar. No se debe especificar la extension .class. Aqui un ejemplo :

java -DmyProp=myValue MyClass x 1

Este comando le dice a la JVM : crea una propiedad llamada myProp y establece su valor a muValue. Luego lanza el archivo MyClass y envia dos argumentos x y 1.

Usando System Properties
Java 5 tiene una clase java.util.Properties que puede ser usada para acceder a informacion persistente del sistema como la version actual de Sistema Operativo,el compilador de Java y la JVM.
Ademas de proveer esas propiedades puedes añadir y recuperar crear tus propias propiedades

import java.util.*;
public class TestProps {
	public static void main(String[] args) {
		Properties p = System.getProperties();
		p.setProperty("myProp", "myValue");
		p.list(System.out);
	}
}

Si este archivo es compilado y ejecutado con :

java -DcmdProp=cmdVal TestProps

Se obtendra una lista como esta :

java.vm.specification.vendor=Sun Microsystems Inc.
user.variant=
os.name=Windows 7
cmdProp=cmdVal
myProp=myValue
sun.jnu.encoding=Cp1252
java.library.path=C:Program Files (x86)Javajdk1.6.0_...
java.specification.name=Java Platform API Specification
java.class.version=50.0
sun.management.compiler=HotSpot Client Compiler
os.version=6.1
...
os.arch=x86
java.io.tmpdir=C:UsersJLSCBU~1AppDataLocalTemp
line.separator=

java.vm.specification.vendor=Sun Microsystems Inc.
user.variant=
os.name=Windows 7
cmdProp=cmdVal
myProp=myValue
...
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
sun.desktop=windows
sun.cpu.isalist=pentium_pro+mmx pentium_pro pentium+m...

Donde … representa varios pares de nombre=valor (el nombre y el valor son llamados tambien key y property). Dos apropiedades fueron agregadas a las propiedades del sistema : myProp = myValue fue adicionado via el metodo setProperty y cmdProp=cmdVal fue adicionado con la opcion -D del comando java.
cuando el valor de la propiedad tiene un espacio en blanco, entonces este valor debe estar entre doble comillas de esta forma :

java -DcmdProp="cmdVal take 2" TestProps

El valor del par name=value debe ir inmediatamente despues de -D, no se permiten espacios.

El metodo getProperty() es usado para recuperar una sola propiedad. Puede ser incocado con un solo argumento que es el nombre o clave de la propiedad. O puede ser invocado con dos argumentos uno es el nombre o clave y el otro es un valor por defecto usado como la propiedad si esta no existe. En ambos casos getPrpperty() retorna un String.

Manejando argumentos de Linea de comandos :
Si tenemos el sgte código :

public class CmdArgs {
	public static void main(String[] args) {
		int x = 0;
		for(String s : args)
		System.out.println(x++ + " element = " + s);
	}
}

Lo compilamos y si lo ejecutamos con este comando :

java CmdArgs x 1

la salida será :

0 element = x
1 element = 1

Hay cierta flexibilidad para declarar el metodo main, por ejemplo el nombre del argumento arreglo no tiene porque llamarse args.Ademas a partir de Java 5 se puede usar var-args para declarar arreglos de variables.
Los sgtes comandos son legales :

static public void main(String[] args)
public static void main(String... x)
static public void main(String bang_a_gong[])

Buscando clases
Cuando se usa el comando javac y aparte de la clase inicial se necesita compilar una clase que no se encuentra en los paquetes predeterminados del JDK , el compilador aplica un algoritmo para hacer una busqueda ordenada de las clases necesarias para compilar las clase iniciales.
Lo mismo sucede con el comando java (invocar al JVM) porque para ejecutar una aplicacion necesita de las clases equivalentes que se usaron en la compilacion.
Por ejemplo si javac necesita de la clase java.util.HashMap, entonces el comando java tambien necesita acceder a java.util.HashMap.

Los comandos java y javac usan varias reglas y criterios para hacer la busqueda de las clases que necesitan.
1. Ambos tienen la misma lista de lugares en donde buscar las clases.
2. Ambos buscan a traves de las listas en el mismo orden.
3. Ambos usan el mismo algoritmo para buscar las clases
4. Empieza buscando en las localizaciones que contiene las clases por defecto con J2SE
5. Los usuarios pueden definir la segunda búsqueda usando classpath
6. Por defecto los classpath pueden se definidos usando las variables de entorno del SO
7. Un classpath puede ser definido en la linea de comandos y sobrescribir el classpath por defecto

Declarando y usando classpaths
Los classpaths consisten de un numero variable de ubicaciones de directorios separados por delimitadores.
En sistemas operativos basados en Unix los fordward slashes son usados para construir ubicaciones de directorios y el delimitador es los dos puntos (:) . Por ejemplo :

-classpath /com/foo/acct:/com/foo

Especifica dos ubicaciones de directorios en las cuales se pueden encontrar las clases , /com/foo/acct y /com/foo. En ambos casos ambos directorios estan unidos a la raiz principal del sistema operativo porque comienzan con /. Es importante recordar que cuando se especifica un subdirectorio , tu NO estas especificanto los directorios superiores.
Por ejemplo en el ejemplo anterior a pesar que se ha especificado /com/foo/acct y /com/foo , el directorio /com no sera buscado.

Una situación comun ocurre cuando javac y java se quejan que no pueden encontrar un archivo class a pesar que usted lo puede ver en el directorio actual. Cuando javac y java buscan los archivos class no buscan por defecto en el directorio actual. Tu debes decirle donde buscar.Una forma de decirle a java o javac que busquen en el directorio por defecto es agregando el punto (.) al classpath.

-classpath /com/foo/acct:/com/foo:.

Este classpath es idéntico al anterior EXCEPTO que este tiene un . al final de la declaracion que indica a javac o java que tambien deben buscar en el directorio actual.
(Recordar que estamos hablando de los archivos class, cuando estemos hablando de javac el cual va a compilar archivos .java, el buscará por defecto en el directorio actual.
Es importante recordar que los classpaths se leen de izquierda a derecha y ademas que una vez encontrada una clase se termina la busqueda.
Puede darse el caso que clases con el mismo nombre pero diferentes ubicaciones sean usadas por una aplicación y que su classpath sea este :

-classpath /com:/foo:.

se obtendra un resultado diferente si el classpath es :

-classpath .:/foo:/com

Finalmente el comando java acepta la abreviación de -classpath a -cp.

Busqueda en paquetes .
Cuando se tiene clases con paquetes la situacion en relacion a los classpath se hace un poco confusa.
Consideremos :
– Una clase dentro de un paquete.
– Un classpath.
– Una ubicación desde donde se ejecuta un comando javac o java.

Con estos tres elementos se puede tener varias formas de armar una configuracion que permita ejecutar una aplicacion Java.

La forma mas simple de la busqueda en paquetes se da cuando se tiene la sgte configuracion

package com.foo;
public class MyClass { public void hi() { } }

Decimos ahora que la clase MyClass es miembro del paquete com.foo y por lo tanto su nombre calificado completo es com.foo.MyClass. Una vez que una clase esta dentro de un paquete la parte de su nombre correspodiente al paquete es atomica, y no se puede dividir ni en un comando en linea de comandos si con una sentencia import.

Ahora veremos como usar com.foo.MyClass en otra clase.

import com.foo.MyClass; // either import will work
import com.foo.*;
public class Another {
	void go() {
		MyClass m1 = new MyClass(); // alias name
		com.foo.MyClass m2 = new com.foo.MyClass(); // full name
		m1.hi();
		m2.hi();
	}
}

La sentencia import se comporta como un alias del nombre calificado completo de la clase
Puedes definir el nombre calificado completo de la clase con una sentencia import (o con una asterisco en la sentencia import). Una vez que has definido el nombre calificado completo, puedes usar el “alias” en tu codigo ( pero el alias se esta refiriendo al nombre calificado completo).

Ahora vamos a ver como el nombre calificado completo de una clase esta relacionado directamente con una estructura de directorios especifica.
Por ejemplo relativo a su directorio actual , la clase cuyo codigo fuente es :

package com.foo;
public class MyClass { public void hi() { } }

debe tener ubicacion aqui :

com/foo/MyClass.class

Para encontrar una clase en un paquete, usted tiene que tener un directorio en su classpath con la entrada de la parte de mas a la izquierda del paquete (“la raíz” del paquete) como un subdirectorio.
Éste es un concepto importante, así es que consideremos otro ejemplo:

import com.wickedlysmart.Utils;
class TestClass {
	void doStuff() {
		Utils u = new Utils(); // simple name
		u.doX("arg1", "arg2");
		com.wickedlysmart.Date d =
		new com.wickedlysmart.Date(); // full name
		d.getMonth("Oct");
	}
}

Aqui como se ve se esta declarando una sentencia import para tener un alias de la clase com.wickedlysmart.Utils pero no lo hacemos para la clase com.wickedlysmart.Date. La única diferencia es que debido a que usamos un alias para com.wickedlysmart.Utils no es necesario escribir el nombre calificado completo de esta clase. En ambos casos el paquete es com.wickedlysmart. Cuando se compile o ejecute TestClass, el classpath debera incluir un directorio con los sgtes atributos :
1. un subdirectorio com (al cual llamaremos el directorio del “paquete raiz” ).
2. un subdirectorio en com llamado wickedlysmart.
3. dos archivos en wickedlysmart llamados Utils y Date.

Finalmente el directorio que tenga todos estos atributos estara accesible via classpath (de dos formas)
a. El path al directorio debe ser absoluto, desde la raiz (del SO , no del paquete) .
b. El path al directorio debe ser un directorio correcto relativo al directorio actual.

Cuando nos referimos a la raíz del SO no se restringe a él (en Windows usualmente C:\) sino también a otras rutas de otras unidades como D:\, E:\, F:\ y asi por el estilo.

Tip : para probar si una ruta será valida y aceptada por la opción -d y -classpath, usar el comando dir de DOS o ls en Linux y si nos muestra el contenido de las ubicaciones requeridas, entonces la ruta es correcta.

Si usamos Linux y queremos comprobar si los sgtes. paths de la opción -classpath de javac son válidos :

-classpath /com/foo/acct:/com/foo:.

Se probará la orden :

ls /com/foo/acct

Y tambien :

ls /com/foo

las cuales deberán mostrar el contenido de las ubicaciones respectivas .

Y si usamos Windows :

-classpath \com\foo\acct:\com\foo:.

Se probará la orden :

dir \com\foo\acct

Y tambien :

dir \com\foo

las cuales deberán mostrar el contenido de las ubicaciones respectivas .

Un ejemplo mas o menos complejo en Windows 7

Supongamos que tenemos un proyecto Web en Netbeans 6.8 sobre Windows 7:
Llamaremos al proyecto FastStore2 el que guardaremos en la sgte ubicación

D:\Codigo\Java

Con la sgte estructura de directorios.

Si queremos demostrar que somos machazos y que el Netbeans sólo lo usamos como editor de textos, entonces tendremos que realizar las sgtes acciones para obtener una clase Java que pueda ser ejecutada por la JVM.

Tenemos la clase JdbcCheckup.java en la ruta :

D:\Codigo\Java\FastStore2\src\java\prueba

Esta clase hace uso de un proveedor de acceso a datos de Oracle 11g R1 para obtener una lista de datos.
El directorio en donde se instalo Oracle, se ubica en :

F:\app

Dentro de esta instalación de Oracle se encuentran varios proveedores de acceso a datos para Java ojdbc6.jar, ojdbc5, ojdbc6_g.jar.jar, etc. Usaremos ojdbc6.jar, que tiene la sgte ruta :

F:\app\Administrador\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar

Lo que se necesita para compilar esta clase es :
– Con la opción -d : el path destino del archivo .class.
– Con la opción -classpath : el path del archivo .jar que se usará para compilar la clase Java.
– El path del archivo fuente Java.

Nota : Es necesario colocar el separador de directorios ; ó : al usar la opcion -classpath aunque se coloque un unico path, notar en el ejemplo.

Para proceder abrimos una ventana de comandos : clic derecho en el ícono de la Ventana de Comandos y Seleccionar “Ejecutar como Administrador” e ingresar la clave si es requerida. Luego nos ubicamos en :

D:\Codigo\Java\FastStore2\src

Con la opción -d usaremos un path que verificaremos con la sgte orden :

dir ..\build\web\WEB-INF\classes

Se hace lo mismo para el path de la opción -classpath :

dir  F:\app\Administrador\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar

Y con el path del archivo fuente de Java:

<code>dir java\prueba\JdbcCheckup.java

En cada caso si el comando dir muestra el contenido del path evaluado, entonces el path es correcto.

Manteniéndonos en la misma ubicación y con la verificación de los path con el comando dir ejecutamos la sgte orden :

javac -d ..\build\web\WEB-INF\classes
-classpath F:\app\Administrador\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar;
java\prueba\JdbcCheckup.java

Con lo que obtendremos el archivo JdbcCheckup.class en : D:\Codigo\Java\FastStore2\build\web\WEB-INF\classes\prueba

Para ejecutar la clase nos ubicaremos en el sgte. path :

D:\Codigo\Java\FastStore2\build\web\WEB-INF\classes

Como la clase necesita enlazar con el proveedor de acceso a datos de Oracle se procederá a añadirlo con la opción -classpath tal como se usó con javac.

Para que la clase JdbcCheckup sea ejecutada por la JVM se debe colocar su nombre calificado completo que es : prueba.JdbcCheckup.

El comando resultante es :

java -classpath  F:\app\Administrador\product\11.1.0\db_1\jdbc\lib\ojdbc6.jar;
prueba.JdbcCheckup

Con estos pasos habremos obtenido la lista de la BD Oracle , compilando y ejecutando la clase manualmente con javac y java.

Otro ejemplo menos complejo
En este ejemplo se tiene una aplicación en Java que es un simulador de Exámenes para una certificación Java (sin roche jeje).

El archivo ejecutable esta ubicado en :

E:\pgjc-engine\no\rwr\engine\App.class

Ubicación del archivo main.
Para ejecutar nos ubicaremos en :

E:\pgjc-engine

y validaremos los paths a usar, desde aquí.
Como no se usará -classpath se validará la ruta de App.class .

dir no\rwr\engine

Ahora procederemos a ejecutar la sgte orden :

java no.rwr.engine.App

Con lo que se obtendra una ejecución correcta.

Podemos tambien ubicarnos en :

E:\

Como se usará -classpath se validará este path.

dir pgjc-engine

Como no estamos ubicados en el directorio raíz de la aplicación debemos juntar la ruta del -classpath con la ruta de App.class .

dir pgjc-engine\no\rwr\engine

Como todo esta correcto, procederemos a ejecutar la sgte orden :

java -classpath pgjc-engine no.rwr.engine.App

Y se obtendrá el mismo resultado .

Una forma de saber si el comando funcionará es comprobando que los argumentos de -classpath junto con el path equivalente al nombre de clase deben dar la ruta correcta del .class de las sgtes formas :

<directorio actual>\<path de clase>

ó

<path de classpath>\<path de clase>

Por ejemplo para el primer comando java

java no.rwr.engine.App

Creará un path de busqueda :

<E:\pgjc-engine>\<no\rwr\engine\App.class>

Para el segundo ejemplo

java -classpath pgjc-engine no.rwr.engine.App

En este caso el único path en -classpath es : pgjc-engine.
Creará un path de busqueda :

<E:\pgjc-engine>\<no\rwr\engine\App.class>

Espero haber esclarecido algunas de sus dudas con respecto al uso de estos comandos.

Anuncios

Un comentario en “Uso de javac y java rev 1.2

  1. No había encontrado explicación como la tuya tan clara acerca del comando javac y las flags que vienen en el libro de certificación te agradezco mucho el haberte tomado el tiempo de publicarlo. Y quisiera aclarar una ultima duda si es que tienes el tiempo de apoyarme:

    Mira tengo problemas para realizar lo siguiente:

    Tengo la clase Saludo en la siguiente ruta
    src\ocja\tutorial\Saludo.java

    la cual instancia 3 objetos de las clases Tierra, Marte, Venus que se encuentran en

    src\ocja\tutorial\planetas\Tierra.java
    src\ocja\tutorial\planetas\Marte.java
    src\ocja\tutorial\planetas\Venus.java

    respectivamente,,, ojo!!! Los 3 archivos fuente los tengo en ésa ruta pero a su vez los tengo con la siguiente leyenda de paquete al principio de cada uno:

    package ocja.tutorial.planetas;

    Estoy situado en la carpeta src en mi linea de comando intentando compilar mi clase Saludo.java con el siguiente comando:

    C:\src> javac -cp ocja\tutorial\planets\;. ocja\tutorial\Saludo.java

    con el resultado siguiente:

    Saludo.java:6: error: cannot find symbol
    Tierra e = new Tierra();
    ^
    symbol: class Tierra
    location: class Saludo
    Saludo.java:6: error: cannot find symbol
    Tierra e = new Tierra();
    ^
    symbol: class Tierra
    location: class Saludo
    Saludo.java:7: error: cannot find symbol
    Marte m = new Marte();
    ^
    symbol: class Marte
    location: class Saludo
    Saludo.java:7: error: cannot find symbol
    Marte m = new Marte();
    ^
    symbol: class Marte
    location: class Saludo
    Saludo.java:8: error: cannot find symbol
    Venus v = new Venus();
    ^
    symbol: class Venus
    location: class Saludo
    Saludo.java:8: error: cannot find symbol
    Venus v = new Venus();
    ^
    symbol: class Venus
    location: class Saludo
    6 errors

    Me podrias explicar si estoy empleando mal el comando o si realmente no se puede compilar classes en diferentes paquetes a la misma vez? o es que no lo puedo compilar porque las fuentes que quiero correr tienen la leyenda package y se tienen que correr diferente? Según el libro de OCJA entendí que si se podía en el siguiente parrafo:

    following compiler invocation, the compiler includes in its compilation any source
    files that are located under the 3rdPartyCode\classes directory, as well as any classes
    located in the present working directory (the period). The -d option (again) will
    place the compiled bytecode into the classes directory.
    javac -d classes -cp 3rdPartyCode\classes\;. GreetingsUniverse
    .java

    Agradecería muchisimo el que me pudieras apoyar Saludos!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s