Buscar
Social
Ofertas laborales ES

Entries in j2se (2359)

viernes
ago102001

Nuevas API de Sun

Sun ha hecho públicas en pocos días las nuevas implementaciones de tres conocidas APIs, o mejor dicho, las nuevas versiones de JMF (2.1.1) y de Java3D (1.2.1_02) y la nueva versión del JDK para Soalris (1.2.2_09).

La nueva versión de JMF se centra en la mejora de rendmiento y facilidad de eso de la multimedia en tiempo real, mientras que en Java3D se han ocupado de corregir numerosos bugs de la versión anterior, así como de incluir nuevos ejemplos para facilitar el aprendizaje.
viernes
ago102001

alphaBeans

Muchos de vosotros conocereis la pagina web de IBM dedicada al opensource (alphaworks), pero quizás no todos conozcais que también tienen una sección dedicada exclusivamente a útiles Java Beans preparaditas para usar. Si alguién no lo sabía, aqui lo suelto.
miércoles
ago012001

Pool de Constantes



El pool de constantes Java







En un fichero de clases java el pool de constantes tiene un función similar a la tabla de símbolos en otros lenguajes. Esta constituido por una serie de referencias simbólicas a los tipos y constantes utilizados por una clase. Una referencia simbólica hacia un miembro de otra clase esta formada por el nombre completo (con paquetes) de la clase y el nombre del método o campo en dicha clase. Los miembros de la clase cuyo pool se examina también aparecen como referencias simbólicas.





En pool de constantes también existen entradas describiendo las constantes de cadena y de datos primitivos, y literales numéricos utilizados en expresiones. El contenido de dichas entradas es el valor constante.





Las referencias simbólicas son sustituidas por referencias directas (punteros o desplazamientos) hacia los miembros que apuntan durante el último paso del enlazamiento de una clase, denominado resolución. La estrategia mas común es no resolver el pool de una clase inmediatamente tras su carga, sino posponer la resolución de las entradas en el pool hasta su primer uso. Durante la resolución de una entrada que apunta hacia un miembro de otra clase se comprueba la existencia y accesibilidad de la otra clase y del campo o método declarado en ella. La accesibilidad viene dada por los modificadores private, public y protected.





El compilador genera un pool de constantes en cada fichero de clases. Cuando la maquina virtual carga una clase construye el pool de constantes runtime en la zona de datos del tipo asociada a dicha clase.





En la siguiente dirección podemos encontrar la especificación de la maquina virtual y en ella detalles sobre el pool de constantes: http://java.sun.com/docs/books/vmspec/2nd-edition/html/VMSpecTOC.doc.html





El pool de constantes en el fichero de clase es precedido de un número que proporciona la cuenta de entradas en el pool. Este número siempre excede en uno a la cantidad de entradas existentes en el pool.









Entradas en el pool







El formato de las tablas siguientes es:







NOMBRE_De_La_Entrada



nº de bytes

nombre del subcampo en la entrada

descripción







Entradas que describen valores literales







CONSTANT_Integer_Info



1 byte

tag

que identifica el tipo, en este caso tiene un

valor de 3



4 bytes

bytes

cuatro bytes sin signo con el valor de una

constante entera (int)





CONSTANT_Float_Info



1 byte

tag

que identifica el tipo, en este caso tiene

un valor de 4



4 bytes

bytes

cuatro bytes sin signo con el valor de una

constante float en orden big-endian





CONSTANT_Long_Info



1 byte

tag

5



8 bytes

bytes

ocho bytes sin signo con el valor de una

constante del tipo long en orden big-endian





CONSTANT_Double_Info



1 byte

tag

6



8 bytes

bytes

ocho bytes sin signo con el valor de una

constante del tipo double en orden big-endian







Las dos últimas entradas ocupan dos posiciones en pool. Por ejemplo si una entrada del tipo CONSTANT_Long_Info esta situada en la entrada numero 5 del pool, la siguiente entrada estaría en el numero 7. Y no existiría entrada con el número 6.







CONSTANT_String_Info



1 byte

tag

8



2 bytes

string_index

indice en el pool de una entrada del tipo

CONSTANT_Utf8_Info conteniendo el literal

de cadena correspondiente a esta entrada.







Mas adelante nos referiremos a estas cinco entradas como entradas de literales.







Entrada describiendo literales de cadena o nombres especiales







CONSTANT_Utf8_Info



1 byte

tag

1



2 bytes

length

longitud en bytes que a continuación describen

una cadena o un nombre de tipo o atributo



length bytes

bytes

caracteres en un formato Utf8 modificado







Esta entrada puede contener el valor de los literales de cadena declarados en el código fuente. Dichas cadenas se convierten a un objeto del tipo String como resultado de la resolución de la entrada. También se almacenan en este tipo de entrada los nombres completos de clases o interfaces, los nombres y descriptores de métodos y campos, y los nombres de los atributos del fichero de clase.





El formato Utf8 modificado es el siguiente:







Rango de caracteres

Representado por



'\u0001' a '\u007F'

0XXX XXXX (1 byte)



'\u0080' a '\u07FF' y '\u0000'

110X XXXX 10XX XXXX (2 bytes)



'\u0800' a '\uFFFF'

1110 XXXX 10XX XXXX 10XX XXXX (3 bytes)







Las diferencias con el formato estándar Utf8 son que no se reconocen los formatos de mas de 3 bytes y que el carácter null se codifica con dos bytes en vez de uno. Esta última diferencia evita que aparezca un byte a cero en una cadena en Java.







Entradas apuntando a tipos o miembros de tipos







CONSTANT_Class_Info



1 byte

tag

7



2 bytes

name_index

indice en el pool de una entrada del tipo

CONSTANT_Utf8_Info conteniendo el nombre

completo de una clase o interfaz, o bien

el descriptor de una matriz. Por ejemplo

“[[D” para “double[][]”.



CONSTANT_NameAndType_Info



1 byte

tag

12



2 bytes

name_index

indice en el pool de una entrada del tipo

CONSTANT_Utf8_Info conteniendo el nombre

simple de un campo o método. El nombre ha

de ser un identificador java valido o

“” para un constructor.



2 bytes

descriptor_index

Indice en el pool de una entrada del tipo

CONSTANT_Utf8_Info conteniendo el descriptor

de un campo o método.





CONSTANT_Fieldref_Info



1 byte

tag

9



2 bytes

class_index

indice en el pool de una entrada del tipo

CONSTANT_Class_Info conteniendo el nombre

completo de la clase o interfaz donde fue

declarado el campo apuntado por esta entrada.



2 bytes

name_and_

type_index

Indice en el pool de una entrada del tipo

CONSTANT_NameAndType conteniendo indices

en pool para dos entradas del tipo

CONSTANT_Utf8_info indicando el nombre

y descriptor del campo.





CONSTANT_Methodref_Info



1 byte

tag

10



2 bytes

class_index

indice en el pool de una entrada del tipo

CONSTANT_Class_Info conteniendo el nombre

completo de la clase (no interfaz) donde

fue declarado el método apuntado por esta

entrada.



2 bytes

name_and_

type_index

Indice en el pool de una entrada del tipo

CONSTANT_NameAndType conteniendo indices

en pool para dos entradas del tipo CONSTANT_Utf8_info

indicando el nombre y descriptor del método.





CONSTANT_InterfaceMethodref_Info



1 byte

tag

11



2 bytes

class_index

indice en el pool de una entrada del tipo

CONSTANT_Class_Info conteniendo el nombre

completo de el interfaz (no clase) donde fue declarado

el campo apuntado por esta entrada.



2 bytes

name_and_

type_index

Indice en el pool de una entrada del tipo

CONSTANT_NameAndType conteniendo indices en

pool para dos entradas del tipo CONSTANT_Utf8_info

indicando el nombre y descriptor del campo.









Ejemplo 1





class Strings {

//Los Literales de cadena sean constantes,estáticos, o instancias, generan

//una entrada CONSTANT_String_Info en el pool de la clase que los declara

String string1 = "Esto es un literal de cadena" ;

final String string2 = "Esto es un literal de cadena"

static final String string3 = "Esto es un literal de cadena"

}





Cada una de las tres lineas generaría una entrada CONSTANT_String_Info en el pool de de la clase Strings. Pero, al

ser el contenido de todas las literales de cadena idéntico únicamente se genera una:





--------------------------------------------------------

8 8 tag (2) CONSTANT_String

0 0 string_index Esto es un literal de cadena

19 11

--------------------------------------------------------





La cual apunta a una entrada CONSTANT_Utf8_Info conteniendo la cadena:





--------------------------------------------------------

1 1 tag (19) CONSTANT_Utf8

0 0 length 28

28 1c

69 45 E bytes Esto es un literal de cadena

115 73 s

116 74 t

111 6f o

32 20

101 65 e

115 73 s

32 20

117 75 u

110 6e n

32 20

108 6c l

105 69 i

116 74 t

101 65 e

114 72 r

97 61 a

108 6c l

32 20

100 64 d

101 65 e

32 20

99 63 c

97 61 a

100 64 d

101 65 e

110 6e n

97 61 a

--------------------------------------------------------





Puede examinar el fichero de clase entero compilando Strings.java y proporcionado el siguiente comando al analizador

de clases ParseClass descargable desde “usuarios.tripod.es/JoseBotella/” :





“ java -classpath c:\ josebotella.parseclass.ParseClass Strings.class “ , el cual produce String.class.txt







Ejemplo 2





class UsandoStrings {

//Las clases que usan literales de cadena declaradas en otras clases

//contienen en su pool entradas CONTANT_Fieldref_Info para las variables

//de instancia (string1) y CONSTANT_String_Info para los campos con el modificador

//“final”

public static void main(String args[]) {

System.out.println(Strings.string3);

System.out.println(new Strings().string2);

System.out.println(new Strings().string1);

}

}





UsandoStrings.class.txt contiene en su pool una entrada CONSTANT_Fieldref_info para la tercera linea, y una

CONSTANT_String_Info para las dos primeras. Puede comprobar que las lineas primera y segunda del método main producen una entrada del tipo String en vez de Fieldref si comenta la tercera linea, compila y utiliza el analizador de clases.





Como ejemplo de entrada CONSTANT_Fielref_Info podemos presentar la producida por la linea tercera en main :





-------------------------------------------------------

9 9 tag (7) CONSTANT_Fieldref

0 0 class_index Strings

5 5

0 0 name_and_type_index string1 Ljava/lang/String;

25 19

--------------------------------------------------------





Esta entrada apunta a las entradas número 5 y 25 del pool. Estas otras a su vez, proporcionan la clase donde se declaró el campo, su nombre y descriptor:





--------------------------------------------------------

7 7 tag (5) CONSTANT_Class

0 0 name_index Strings

24 18

--------------------------------------------------------



--------------------------------------------------------

12 c tag (25) CONSTANT_NameAndType

0 0 name_index string1

34 22 "

0 0 descriptor_ index Ljava/lang/String;

35 23 #

--------------------------------------------------------





Donde puede ver que estas entradas apuntan a otras de número 24, 34 y 35. En el fichero UsandoStrings.class.txt se observa que tales entradas, del tipo CONSTANT_Utf8_Info, contienen respectivamente las cadenas: Strings, string1 y Ljava/lang/String;







Ejemplo 3







class NumericosFinal {

//Todos los literales constantes de tipos primitivos generan entradas

//CONSTANT_Fieldref en el pool de la clase que los declara.

//Ademas existen las apropiadas entradas de literales independientemente

//del valor de la constante

final byte byteF = (byte) 127 ;

final short shortF = (short) 3;

final int intF = 32767;

final long longF = 1L;

final float floatF = 1.5F;

final double doubleF = 1.55;

final char charF = 'B';

final boolean booleanF = true;

}





En el fichero NumericosFinal.class.txt puede ver que se han generado entradas CONSTANT_Fieldref para cada uno de los campos. Y que el valor de cada constante se ha almacenado en una entrada apropiada tal como se relaciona a continuación:





boolean, byte, short, char, int............CONSTANT_Integer_Info double..............................................CONSTANT_Double_Info float..................................................CONSTANT_Float_Info long..................................................CONSTANT_Lonf_Info String................................................CONSTANT_String_Info





A titulo de ejemplo la entrada para el campo booleanF es:





--------------------------------------------------------

3 3 tag (38) CONSTANT_Integer

0 0 bytes 1

0 0

0 0

1 1

--------------------------------------------------------







Ejemplo 4







Ahora una clase que utiliza la anterior:





class UsandoNumericosFinal {

//Las clases que usan literales numéricos constantes declarados

//en otras clases no contendrán en su pool entradas del tipo

//CONSTANT_Fieldref, sino de los tipos literales. O bien, ninguna entrada

//dependiendo del valor de la constante

public static void main(String args[]) {

NumericosFinal nf = new NumericosFinal();

System.out.println(nf.booleanF);

System.out.println(nf.byteF);

System.out.println(nf.intF);

System.out.println(nf.longF);

System.out.println(nf.shortF);

System.out.println(nf.floatF);

System.out.println(nf.doubleF);

System.out.println(nf.charF);

}

}





En su correspondiente fichero UsandoNumericosFinal.class.txt se observa que que no existen entradas del tipo Fieldref. Únicamente contamos con :





--------------------------------------------------------

4 4 tag (8) CONSTANT_Float

63 3f ? bytes 1.5

192 c0 À

0 0

0 0

--------------------------------------------------------



--------------------------------------------------------

6 6 tag (10) CONSTANT_Double

63 3f ? bytes 1.55

248 f8 ø

204 cc Ì

204 cc Ì

204 cc Ì

204 cc Ì

204 cc Ì

205 cd Í

--------------------------------------------------------





Estas entradas se refieren a los campos floatF y doubleF. Luego, ¿como emplea nuestro programa el resto de los campos?

La respuesta nos la proporciona el desensamblador javap de la forma siguiente: “javap -c UsandoNumericosFinal”





El comando anterior produce la salida:





Method void main(java.lang.String[])

0 new #2 (Class NumericosFinal)

3 dup

4 invokespecial #3 (Method NumericosFinal())

7 astore_1

8 getstatic #4 (Field java.io.PrintStream out)

11 iconst_1 //Se ocupa del boolean

12 invokevirtual #5 (Method void println(boolean))

15 getstatic #4 (Field java.io.PrintStream out)

18 bipush 127 //Se ocupa del byte

20 invokevirtual #6 (Method void println(int))

23 getstatic #4 (Field java.io.PrintStream out)

26 sipush 32767 //Se ocupa del int

29 invokevirtual #6 (Method void println(int))

32 getstatic #4 (Field java.io.PrintStream out)

35 lconst_1 //Se ocupa del long

36 invokevirtual #7 (Method void println(long))

39 getstatic #4 (Field java.io.PrintStream out)

42 iconst_3 //Se ocupa del short

43 invokevirtual #6 (Method void println(int))

46 getstatic #4 (Field java.io.PrintStream out)

49 ldc #8 (Real 1.5) //Se ocupa del float

51 invokevirtual #9 (Method void println(float))

54 getstatic #4 (Field java.io.PrintStream out)

57 ldc2_w #10 (Double 1.55) //Se ocupa del double

60 invokevirtual #12 (Method void println(double))

63 getstatic #4 (Field java.io.PrintStream out)

66 bipush 66 //Se ocupa del char

68 invokevirtual #13 (Method void println(char))

71 return





Como puede verse en el método main existen una serie de bytecodes que evitan la creación de entradas en el pool para

todos los campos excepto doubleF y floatF. Ello depende del valor que toman los campos.

Por ejemplo, la instrucción iconst_1 coloca un 1 en el pool de operandos para representar el valor true, y bipush 127, coloca dicho valor para el byte. Sin embargo, si pretendiésemos asignar 32768 a intF, no podría emplearse sipush 32768 para tal fin puesto que el bytecode sipush coloca en la pila de operandos un número dentro del rango short; como resultado la asignación de 32768 a un int debería hacerse con una entrada en el pool. Esta es la forma empleada en las lineas 57 y 49. ¿Por que?, porque no existe ninguna instrucción que sea capaz de asignar los valores 1.5 y 1.55 sin ayuda de una entrada en el pool. De haber querido asignar 1.0, el compilador hubiese empleado los bytecodes fconst_1 o dconst_1.

En definitiva, cuando el compilador juzga que un determinado bytecode puede evitar la referencia a una entrada en el pool, buscando una reducción en el numero de bytes o una ejecución mas rápida, utiliza dicha instrucción. Los posibles bytecodes empleados por el compilador a tal efecto son: bipush, sipush, iconst_(0,1,2,3,4,5,m1), dconst_(0,1), fconst_(0,1,2) y lconst_(0,1) . Puede encontrar una descripción de los bytecodes en el libro Inside the Java 2 Virtual Machine de Bill Venners.





En este programa el compilador no emplea entradas de literales cuando puede evitarlo. Solo en los casos doubleF y floatF hace referencia a entradas del tipo CONSTANT_Double y CONSTANT_Float existentes en su propio pool. Pues bien, estas entradas son copias de las existentes en el pool de la clase NumericosFinal.





Una última observación. En el fichero javapNumericosFinal.txt , obtenido con javap, también puede observarse la exclusión, siempre que sea posible, de las referencias al pool de la clase NumericosFinal. En esta clase, el constructor, a pesar de tener a su disposición entradas en el pool para cada una de las constantes, simplemente las evita.







Ejemplo 5







class NumericosFinalStatic {

//Las clases que declaran constantes estáticas no cuentan en su pool con entradas

//del tipo Fieldref sino de los tipos literales apropiados para contener el valor

final static byte byteSF = (byte) 12 ;

final static short shortSF = (short) 2;

final static int intSF = 32768;

final static long longSF = 5L;

final static float floatSF = 1.0F;

final static double doubleSF = 1.0;

final static char charSF = 'a';

final static boolean booleanSF = false;

}





En el fichero NumericosFinalStatic.class.txt no existe ninguna entrada CONSTANT_Fielref, pero si las correspondientes entradas CONSTANT_Integer etc.

Como todas los campos estáticos son constantes el método de inicialización de clase (<clinit>) no tiene código para inicializar los campos estáticos. De hecho, ni siquiera existe tal método en javapNumericosFinalStatic.txt







Ejemplo 6





class UsandoNumericosFinalStatic {

//De nuevo no existen entradas del tipo Fieldref, sino del tipo literal apropiado

//para el valor, siempre y cuando el valor no pueda ser computado por uno de los

//bytecodes vistos anteriormente

public static void main(String args[]) {

NumericosFinalStatic nfs = new NumericosFinalStatic();

System.out.println(nfs.booleanSF);

System.out.println(nfs.byteSF);

System.out.println(nfs.intSF);

System.out.println(nfs.longSF);

System.out.println(nfs.shortSF);

System.out.println(nfs.floatSF);

System.out.println(nfs.doubleSF);

System.out.println(nfs.charSF);

}

}





En el fichero UsandoNumericosFinalStatic.class.txt puede observarse la inexistencia de entradas Fieldref. Si figuran, en cambio, las dos entradas:





--------------------------------------------------------



3 3 tag (7) CONSTANT_Integer

0 0 bytes 32768

0 0

128 80 ?

0 0

--------------------------------------------------------

5 5 tag (8) CONSTANT_Long

0 0 bytes 5

0 0

0 0

0 0

0 0

0 0

0 0

5 5

--------------------------------------------------------





Las cuales se corresponden con los valores que no pueden ser expresados de otra forma, tal como se pone de manifiesto en

el fichero javapUsandoNumericosFinalStatic.txt







Ejemplo 7







class Numéricos {

//Cuando no son constantes las entrada de los tipos literales se generan únicamente

//si su valor no permite utilizar un bytecode que suponga un ahorro en bytes o

//mayor velocidad. En cambio se generan entradas Fieldref para todos los campos.

//Este comportamiento no depende del carácter estático o instancia del campo.

byte bipush = 127;

short bipushUnShort = 127;

short sipushUnShort = 128;

char bipusAChar = 'a';

char CONSTANT_Integer_2 = '\uFFFF' ;

int CONSTANT_Integer = 32768;

int sipush = 32767;

int bipushUnInteger = 127;

long CONSTANT_Long = 2;

long lconst_1 = 1;

float fconstant_2 = 2;

float CONSTANT_Float = 3;

double dconstant_1 = 1;

double CONSTANT_Double = 2;

static int CONSTANT_INTEGER_AStaticInt = 32769;

static int bipushUnIntegerStatic = 126;

}





En el fichero Numericos.class.txt se observa que los campos que generan entradas literales en el pool son nombrados empezando por CONSTANT. El resto poseen un nombre que recuerda la instrucción de la maquina virtual usada en lugar de una entrada en el pool. Todos los campos producen entradas CONSTANT_Fieldref.

En el fichero javapNumericos.txt se proporcionan estos bytecodes.







Ejemplo 8







class UsandoNumericos {

//Si una clase utiliza variables de otra, ya sean estáticas o no, su pool no contiene

//entradas de los tipos literales sino Fieldref

public static void main(String args[]) {

Numéricos n = new Numéricos();

System.out.println(n.CONSTANT_Long);

System.out.println(n.lconst_1);

System.out.println(Numericos.CONSTANT_INTEGER_AStaticInt);

System.out.println(Numericos.bipushUnIntegerStatic);

}

}





En el fichero UsandoNumericos.class.txt vemos cuatro entradas CONSTANT_Fieldref. Para los curiosos también

proporciono javapUsandoNumericos.txt donde los bytecodes getfield o getstatic acceden a los campos correspondientes.







Conclusiones de los ejemplos 1 a 8







Estos ejemplos han pretendido descubrir la relación entre el tipo de entrada producida en el pool y el tipo de campo.

Estas son las conclusiones:





a) Variables estáticas y de instancia .





La clase que declara variables contiene en su pool entradas Fielref para ellas. También contiene entradas del tipo Integer,

Long, Double, Float o String (literales) para expresar los valores asignados a las variables, siempre y cuando dicho valor no

pueda expresarse con un bytecode. La clase que usa variables definidas en otras clases contiene en su pool entradas del tipo

Fieldref para hacer referencia a las variables independientemente de su valor.





b) Constantes estáticas.





Las clases que declaran constantes estáticas cuentan en su pool con entradas de los tipos literales independientemente del

valor de la constante. La clase que usa constantes estáticas definidas en otras clases contendrá en su pool entradas de los

tipos literales siempre y cuando no exista un bytecode que pueda expresar el valor de la constante.





c) Constantes de instancia.





La clase que declara constantes no estáticas contiene en su pool entradas Fielref para todas ellas. Por lo demás, siguen el

mismo patrón que las constantes estáticas al generar entradas en el pool.







Ejemplo 9





En esta clase tenemos cinco ocurrencias del literal 90 double. Todas ellas generan una sola entrada CONSTANT_Double en

el pool. El fichero ExpresionNumerica.class.txt expone dicha entrada.





class ExpresionNumerica {

int expresión = (int) (Math.sin(90) + Math.sin(90) + Math.sin(90) );

double d1 = 90.0;

double d2 = 90.0;

}







Ejemplo 10





class Métodos {

//Los métodos declarados en una clase no originan entradas

//CONSTANT_Methodref en el pool de la clase

static int i = 3;

static int MetodoEstatico(int inti) { return inti; }

void MetodoInstancia() { }

}





En el fichero Metodos.class.txt no existe ninguna entrada Methodref para los métodos declarados en la clase. Solo la

invocación de los mismos las produciría. La única invocación de método es la del constructor de la clase padre:





--------------------------------------------------------

10 a tag (1) CONSTANT_Methodref

0 0 class_index java/lang/Object

4 4

0 0 name_and_type_index (init) ()V

17 11

--------------------------------------------------------





La entrada número 4 es del tipo CONSTANT_Class e indica la clase donde reside el método que se invocara. La número

17 es del tipo CONSTANT_NameAndType y apunta a su vez a otras dos del tipo CONSTANT_Utf8. Por último dichas

entradas contienen las cadenas con el nombre del método “<init>” y su descriptor “( )V”.





La invocación del constructor padre se produce dentro del constructor de la propia clase Métodos como vemos en la salida

de “javap -c Metodos” :





class Métodos extends java.lang.Object {

static int i;

Métodos();

static int MetodoEstatico(int);

void MetodoInstancia();

static {};

}

Method Métodos()

0 aload_0

1 invokespecial #1 (Method java.lang.Object())

4 return

Method int MetodoEstatico(int)

0 iload_0

1 ireturn

Method void MetodoInstancia()

0 return

Method static {}

0 iconst_3

1 putstatic #2 (Field int i)

4 return





Vemos dos métodos creados automáticamente por el compilador. El constructor por defecto cuyo nombre es “<init>” y el

inicializador de clase “<clinit>”. Aunque javap elige mostrarnos otros nombres. La instrucción “invokespecial #1” invoca el

método al cual la entrada número uno del pool referencia, es decir el constructor padre.

El método <clinit>, (aquí static), inicializa las variables estáticas y nunca es llamado por el programador, sino por la propia

maquina virtual . Esto determina que nunca existira una entrada en el pool para él.







Ejemplo 11





class UsandoMetodos {

public static void main(String[] args) {

Metodos.MetodoEstatico(1);

Métodos me = new Métodos();

me.MetodoInstancia();

}

}





El fichero UsandoMetodos.class.txt muestra dos entradas en el pool. Invocando una al constructor padre de esta clase, y la

otra al constructor de la clase Métodos producida por la instrucción “new”. También aparecen la entradas siguientes

“apuntando simbólicamente a los métodos declarados en el ejemplo 10:





--------------------------------------------------------

10 a tag (2) CONSTANT_Methodref

0 0 class_index Métodos

3 3

0 0 name_and_type_index MetodoEstatico (I)I

17 11

--------------------------------------------------------

--------------------------------------------------------

10 a tag (5) CONSTANT_Methodref

0 0 class_index Métodos

3 3

0 0 name_and_type_index MetodoInstancia ()V

19 13

--------------------------------------------------------





En estos ejemplos la clase apuntada por class_index corresponde al tipo de la referencia sobre la cual se invoca el método.

En nuestro caso las referencias son “me” y “Metodos”.







Ejemplo 12





class SubMetodos extends Métodos implements Interfaz {

//El compilador hace que class_index de CONSTANT_Methodref o de

//CONSTANT_InterfaceMethodref apunte al tipo donde reside la declaración, del método

//que se esta invocando, mas cercana a la clase desde donde se invoca.

//El compilador busca el método en la clase o interfaz dada por la expresión sobre la

//que se produce la invocación del método.

//El compilador busca tanto métodos declarados en ese tipo como heredados de sus

//supertipos. class_index apunta al tipo padre si el método fue heredado y al hijo

//si el método fue sobrescrito.

public void MetodoInstancia() {

//sobrescribe el método padre

//que no haga nada no es relevante

}

public static void main(String[] args) {

new SubMetodos().test();

}

void test() {// class_index apuntara a...

super.MetodoInstancia(); //...Metodos 1

this.MetodoInstancia(); //...SubMetodos 5

this.MetodoEstatico(1); //...Metodos 9

MetodoInstancia(); //...SubMetodos 14

Métodos met = new SubMetodos();

met.MetodoInstancia(); //...Metodos 26

Interfaz inter = new SubMetodos();

inter.MetodoInstancia(); //...Interfaz 38

}

}



interface Interfaz {

void MetodoInstancia() ;

}





Deseamos comprobar el tipo apuntado por class_index en cada una de las invocaciones anteriores.

En el fichero SubMetodos.class.txt se pueden observar las siguientes entradas:





--------------------------------------------------------

10 a tag (5) CONSTANT_Methodref

0 0 class_index Métodos

9 9

0 0 name_and_type_index MetodoInstancia ()V

24 18

--------------------------------------------------------

10 a tag (6) CONSTANT_Methodref

0 0 class_index SubMetodos

2 2

0 0 name_and_type_index MetodoInstancia ()V

24 18

--------------------------------------------------------

10 a tag (7) CONSTANT_Methodref

0 0 class_index Métodos

9 9

0 0 name_and_type_index MetodoEstatico (I)I

25 19

--------------------------------------------------------

11 b tag (8) CONSTANT_InterfaceMethodref

0 0 class_index Interfaz

10 a

0 0 name_and_type_index MetodoInstancia ()V

24 18

--------------------------------------------------------





En la salida de “ javap -c Submetodos “ encontraremos las instrucciones de la maquina virtual que las utilizan:





Method void test()

0 aload_0

1 invokespecial #5 (Method void MetodoInstancia())

4 aload_0

5 invokevirtual #6 (Method void MetodoInstancia())

8 iconst_1

9 invokestatic #7 (Method int MetodoEstatico(int))

12 pop

13 aload_0

14 invokevirtual #6 (Method void MetodoInstancia())

17 new #2 (Class SubMetodos)

20 dup

21 invokespecial #3 (Method SubMetodos())

24 astore_1

25 aload_1

26 invokevirtual #5 (Method void MetodoInstancia())

29 new #2 (Class SubMetodos)

32 dup

33 invokespecial #3 (Method SubMetodos())

36 astore_2

37 aload_2

38 invokeinterface (args 1) #8 (InterfaceMethod void MetodoInstancia())

43 return





En el programa figura en cada invocación de método la linea en este listado donde se encuentra el bytecode que realiza la

llamada. Por ejemplo: “ super.MetodoInstancia() //Métodos 1 “. En el listado de arriba la linea comenzando por 1 muestra

el bytecode “invokeespecial #5” utilizado para realizar la llamada del método. El dígito 5 indica la entrada en el pool que

hace referencia al método llamado. Ademas en el comentario de la linea se indica que el class_index de la entrada ( #5 )

producida en el pool por dicha linea es del tipo “Metodos”.





En “ super.MetodoInstancia(); ” super tiene un tipo que es padre del que posee this: Métodos.

En “ this.MetodoInstancia(); ” this tiene el tipo SubMetodos.

En estos dos ejemplos, el tipo dado por la expresión sobre la cual se realiza la invocación del método declaró un método

cuyo descriptor coincide con el del método que se busca. Cumpliéndose ademas que dicho método es accesible según las

normas de los modificadores de acceso (public, protected, private), el tipo de la expresión es seleccionado por el compilador

para ser apuntado por class_index.





En “ this.MetodoEstatico() “ this, naturalmente, sigue teniendo el tipo “SubMetodos” pero el “MetodoEstatico” fue definido

an la clase padre y heredado, no sobrescrito. Luego class_index de la entrada en el pool número 7 apunta a la clase

Métodos. El compilador observó que la clase “SubMetodos” no definía el método que se esta invocando y buscó entre sus

supertipos. El carácter estático del método no varia el comportamiento descrito respecto de un método de instancia ni final.





En “ MetodoInstancia(); ” el tipo de la “expresión” es “SubMetodos”. Porque esta invocación es equivalente a usar “this”.

La clase “SubMetodos” si declaró ( sobrescribió ) el método invocado, luego esta es la clase apuntada por class_index.





En “ met.MetodoInstancia(); ” el tipo de “met” es la clase con la fue declarado. Esto es, “Metodos”.





En “ inter.MetodoInstancia(); ” el tipo de “inter” es “Interfaz”. En dicho interface fue declarado un método con el mismo

descriptor que aquel que se esta invocando, luego es dicho tipo el que aparece en class_index de la entrada

CONSTANT_InterfaceMethodref. Este tipo de entrada solo se genera cuando se invoca un método declarado en un

interface, pero únicamente si la invocación se realiza a través de una referencia cuyo tipo es un interface. En nuestro ejemplo

la referencia es “inter”.







Conclusiones de los ejemplos 10 a 12





Las entradas CONSTANT_InterfaceMethodref y CONSTANT_Methodref son generadas por la invocación de un método

en una clase. No los son por la declaración de métodos.

El tipo apuntado por class_index de una entrada en el pool del tipo CONSTANT_InterfaceMethodref o

CONSTANT_Methodref es el tipo de la “referencia o expresión” sobre la cual se produce la invocación del método,

siempre y cuando dicho tipo contenga una declaración del método invocado. En caso contrario el compilador buscara el

primer supertipo que lo declare.

Una entrada CONSTANT_InterfaceMethodref en el pool es creada únicamente por la invocación de un método declaradoen un interface, si esta invocación se produce sobre una referencia del tipo interface.
















José Botella.



Para cualquier duda o tirón de orejas, e-mail a:
Jose139090_ARROBA_netscape.net






Este artículo esta republicado de la página personal de José Botella. Consultalá para tener acceso a la revisión más actual del mismo.




viernes
jul272001

Java Web Start y las aplicaciones cliente

Esta si que es una herramienta interesante para el despliegue de aplicaciones cliente.

Si una de las quejas que se ponia a Java era la necesidad de instalar el JRE, con esta nueva herramienta de Sun, la aplicaciones web de java (lease applets) dejarán de encontrar los problemas existentes entre navegadores, con lo cual el usuario podrá ejecutarlas facilmente, y los desarrolladores dejaran de "acordarse de los muertos de su jefe" cada vez que tengan que transformar una aplicación en applet, cosa muy sencilla por lo general, pero que los navegadores convertían en pesadilla.

A parte deso, podemos, por supuesto, ejecutar aplicaciones independientes, así como hacerlo desde el menú de inicio y el escritorio de Windows debido a su integración en dichos sistemas.

De momento solo esta disponible para Windows, pero teniendo en cuenta que es donde más falta hará por el conjunto de usuarios y por la política de Microsoft, tampoco es para quejarse. Ya vendrá para "el pingüino" :-).
jueves
jul262001

Java USB API

Java sigue su camino imparable hace convertirse en un lenguaje "sin limites". Aqui tenemos la revision 0.9.0 de el API para manejo de USB con Java.
Quien iba a decir cuando todo el mundo decia que Java solo era para hacer applets que llegaria donde esta, y aun no ha llegado el final!.