You are on page 1of 240

Tutorial para el Examen de certificacion:

SCJP 1.2
Traducción del tutorial de Marcus Green.

RuGI
Isaac Ruiz Guerra
rugi@javahispano.org

javaHispano
Tu lenguaje, tu comunidad.
Versión Julio del 2003.
Tutorial para el examen de certificación: SCJP 1.2

El presente documento es una traducción/adaptación del tutorial de Marcus Green


correspondiente a la versión de diciembre del 2002. Dicho tutorial cubre los objetivos
correspondientes al examen SCJP 1.2.

La mayor parte de este documento cubre tambien los objetivos para la versión 1.4
únicamente se deben pasar por alto las secciones 8 y 11, y agregar el tema de Aserciones.

Esta traducción se realizó con la colaboración de:

Nombre: Sección:
Isaac Ruiz Guerra 1, 2, 3, 4, 6, 8, 9, 10
Joslyn Flores Romero 7
Francisco Fernández Miser 5
Alberto Molpeceres 11

Puedes hacer cualquier comentario sobre la traducción a rugi@javahispano.org

La dirección del tutorial de Marcus Green:


http://www.jchq.net/certkey/index.htm

Un artículo de Emili Miedes de Elías sobre Aserciones:


http://www.javahispano.org/articles.article.action?id=57

Este documento forma parte del proyecto “Examen de Certificación”:


http://www.javahispano.org/text.viewer.action?file=proyectos

Copyright (c) 2003,Isaac Ruiz Guerra. Este documento puede ser distribuido solo bajo
los términos y condiciones de la licencia de Documentación de javaHispano v1.0 o
posterior (la última versión se encuentra en http://www.javahispano.org/licencias/).

2
javaHispano. Tu comunidad, tu lenguaje.

Sección 1. Declaración y control de Acceso ......................7


Objetivo 1........................................................................................................................ 7
Arreglos................................................................................................................... 7
Declaración sin asignación. ........................................................................................ 7
Creación y Declaración Simultanea............................................................................ 8
Arreglos Java VS Arreglos C/C++ . .................................................................... 8
Los arreglos conocen su tamaño. ........................................................................... 9
Arreglos Java VS Arreglos VB............................................................................ 9
Combinar declaración con inicialización.................................................................. 10
Objetivo 2...................................................................................................................... 15
Comparando las clases de C++/VB con las de Java. ................................................ 15
El rol de las clases en Java........................................................................................ 15
La clase más sencilla................................................................................................. 16
Creando una clase sencilla- HelloWorld................................................................... 16
La magia del nombre main ....................................................................................... 16
Creando una instancia de una Clase.......................................................................... 17
Creando Métodos. ..................................................................................................... 18
Variables Automáticas .............................................................................................. 19
Modificadores y Encapsulamiento............................................................................ 20
Usando modificadores en combinación .................................................................... 26
Objetivo 3...................................................................................................................... 35
Nota de este objetivo................................................................................................. 35
¿Qué es un constructor? ............................................................................................ 35
¿Cuándo proporciona Java el constructor predefinido?............................................ 35
El prototipo del constructor predefinido ................................................................... 37
Objetivo 4...................................................................................................................... 43
Nota de este objetivo................................................................................................. 43
Métodos en la misma clase ....................................................................................... 43
Métodos en una subclase. ......................................................................................... 44
Sección 2. Control de Flujo y Manejo de Excepciones. ...........47
Objetivo 1...................................................................................................................... 47
La sentencia if/else.................................................................................................... 47
La Sentencia switch................................................................................................... 48
Argumentos validos para las sentencias if y switch. ................................................. 49
El operador ternario ?................................................................................................ 49
Objetivo 2...................................................................................................................... 55
La sentencia for......................................................................................................... 55
Los ciclos while y do, nada inesperado................................................................. 56
La sentencia goto, ¿ciencia o religión? ..................................................................... 57
Break y Continue ...................................................................................................... 57
Saltar a una Etiqueta. ................................................................................................ 58
Objetivo 3...................................................................................................................... 64
Comparando con Visual Basic y C/C++................................................................... 64
La Cláusula finally .................................................................................................... 65
Sobrescribiendo métodos que lanzan excepciones ................................................... 66

3
Tutorial para el examen de certificación: SCJP 1.2

Sección 3. Recolector de basura –Garbage Collector- ............72


Objetivo 1...................................................................................................................... 72
¿Por qué querrías utilizar el recolector de basura? ................................................... 72
Java y el recolector de basura. .................................................................................. 72
Sección 4. Fundamentos del lenguaje. ...........................76
Objetivo 1...................................................................................................................... 76
Nota sobre este objetivo............................................................................................ 76
La sentencia package ................................................................................................ 76
La sentencia import ............................................................................................... 77
Clases y la declaración de clases internas................................................................. 77
Clases internas declaradas dentro de métodos .......................................................... 79
Visibilidad de campos para clases definidas dentro de un método........................... 80
Creando una interface ............................................................................................... 81
Objetivo 2...................................................................................................................... 85
Objetivo 3...................................................................................................................... 87
Objetivo 4...................................................................................................................... 90
Variables ................................................................................................................... 90
Arreglos..................................................................................................................... 91
Objetivo 5...................................................................................................................... 95
Tamaño de los tipos primitivos enteros .................................................................... 95
Declarando literales enteros...................................................................................... 95
Tamaño de los tipos primitivos de coma flotante ..................................................... 96
Indicando tipos de datos con un literal sufijo ........................................................... 97
Los tipos boolean y char........................................................................................... 97
Declarando literales String ................................................................................... 99
Sección 5. Operadores y Asignaciones ..........................102
Objetivo 1.................................................................................................................... 102
El operador instanceof ....................................................................................... 102
El operador + .......................................................................................................... 103
Asignando variables primitivas de tipos diferentes ................................................ 104
Asignando referencias de objetos de diferentes tipos. ............................................ 105
Operadores de desplazamiento de bits.................................................................... 106
Operadores de desplazamiento con signo << y >> ................................................. 107
Desplazamiento sin signo a la derecha >>>............................................................ 108
Applet BitShift ........................................................................................................ 108
Objetivo 2.................................................................................................................... 113
Diferencia entre el método equals y el operador = = .............................................. 113
Usando el método equals con Strings ..................................................................... 113
Usando el método equals con la Clase Boolean ..................................................... 114
Usando el método equals con objetos..................................................................... 115
Objetivo 3.................................................................................................................... 119
El efecto corto circuito con los operadores lógicos. ............................................... 119
Operadores a nivel de bits....................................................................................... 120
Pensando en binario ................................................................................................ 120
Objetivo 4.................................................................................................................... 124
Nota sobre este objetivo.......................................................................................... 124
Referencias de Objetos como parámetros de métodos. .......................................... 124

4
javaHispano. Tu comunidad, tu lenguaje.

Primitivas como parámetros de métodos ................................................................ 125


Sección 6. Sobrecarga, sobreescritura, tipos en tiempo de
ejecución y orientación a objetos .............................128
Objetivo 1) .................................................................................................................. 128
Relaciones “es un” y “tiene un”.............................................................................. 128
Encapsulamiento ..................................................................................................... 128
Tipos en Tiempo de ejecución ................................................................................ 130
Objetivo 2) .................................................................................................................. 135
Comentario sobre el objetivo .................................................................................. 135
Sobrecarga de métodos ........................................................................................... 135
Sobrescritura de métodos....................................................................................... 136
Invocando constructores de clases base.................................................................. 137
Invocando constructores con this() ..................................................................... 138
El constructor y la jerarquía de clases..................................................................... 139
Objetivo 3) .................................................................................................................. 146
Nota sobre este objetivo.......................................................................................... 146
Instanciando una clase ............................................................................................ 146
Clases internas ........................................................................................................ 146
Clases Anidadas de nivel Superior (Top Level) ..................................................... 147
Clases Miembro ...................................................................................................... 147
Clases creadas dentro de métodos........................................................................... 148
Clases anónimas...................................................................................................... 148
Sección 7. Threads ............................................152
Objetivo 1) .................................................................................................................. 152
¿Qué es un Thread ?................................................................................................ 152
Las dos formas de crear un Hilo (Thread) .............................................................. 152
Instanciando e Iniciando un hilo. ............................................................................ 153
Objetivo 2) .................................................................................................................. 157
Comentario de este objetivo.................................................................................... 157
Razones por las que un thread puede ser bloqueado............................................... 157
Objetivo 3) .................................................................................................................. 161
¿Por qué necesitarías el protocolo wait/notify? ...................................................... 161
synchronized ........................................................................................................... 161
wait/notify ............................................................................................................... 162
Sección 8. El paquete java.awt y su disposición ...............167
Objetivo 1.................................................................................................................... 167
Nota sobre este objetivo.......................................................................................... 167
Comparando la disposición de componentes de Java y Visual Basic..................... 167
La filosofía de los administradores de disposición ................................................. 167
Administradores de disposición que debes conocer para el examen. ..................... 169
Responsabilidades de los Administradores de Disposición VS los Contenedores . 169
Curiosidades del administrador BorderLayout ....................................................... 170
El administrador de disposición GridLayout .......................................................... 171
GridBagLayout ....................................................................................................... 172
Usando gridx y gridy para sugerir la posición de un componente.......................... 175
ipadx y ipady para controlar el relleno interior de los componentes ...................... 176
Componentes dentro de un panel utilizando GridBagLayout................................. 178

5
Tutorial para el examen de certificación: SCJP 1.2

Fijando componentes dentro de la cuadrícula......................................................... 180


Elementos GridBag no cubiertos por este ejercicio............................................... 182
Objetivo 2.................................................................................................................... 189
El modelo oyente -Listener- de eventos.................................................................. 189
El modelo de eventos del JDK 1.1.......................................................................... 189
Sección 9. El paquete java.lang.Math ..........................196
Objetivo 1.................................................................................................................... 196
Nota sobre este objetivo.......................................................................................... 196
abs ........................................................................................................................... 196
ceil........................................................................................................................... 196
floor......................................................................................................................... 197
max y min ............................................................................................................... 197
random .................................................................................................................... 198
round ....................................................................................................................... 198
sin cos tan................................................................................................................ 199
sqrt........................................................................................................................... 199
Resumen.................................................................................................................. 199
Objetivo 2.................................................................................................................... 203
Nota sobre este objetivo.......................................................................................... 203
Sección 10. El paquete java.util ..............................206
Objetivo 1.................................................................................................................... 206
Nota sobre este objetivo.......................................................................................... 206
Las colecciones antiguas......................................................................................... 206
Las nuevas colecciones ........................................................................................... 206
Set ........................................................................................................................... 207
List .......................................................................................................................... 207
Map ......................................................................................................................... 207
Usando Vectores ..................................................................................................... 208
Usando Hashtables.................................................................................................. 209
BitSet....................................................................................................................... 209
Sección 11. El paquete java.io ................................214
Objetivo 1.................................................................................................................... 214
Objetivo 2.................................................................................................................... 222
Objetivo 3.................................................................................................................... 228
Objetivo 4.................................................................................................................... 229
FileInputStream and OutputStream ........................................................................ 229
BufferedInputStream y BufferedOutputStream...................................................... 230
DataInputStream y DataOutputStream ................................................................... 230
La clase File......................................................................................................... 231
RandomAccesFile ................................................................................................... 231
Objetivo 5.................................................................................................................... 235
FileInputStream and FileOutputStream .................................................................. 235
RandomAccessFile ................................................................................................. 236

6
javaHispano. Tu comunidad, tu lenguaje.

Sección 1. Declaración y control de Acceso


Objetivo 1.
Escribir código que declare, construya e inicie arreglos de cualquier tipo base, usando
cualquiera de las formas permitidas, para declaración y para inicialización.

Arreglos.
Los arreglos en Java son similares en sintaxis a los arreglos en otros lenguajes
como C/C++ y Visual Basic. Sin embargo, Java elimina la característica de C/C++
mediante la cual puedes pasar los corchetes ([]) accediendo a los elementos y obteniendo
sus valores utilizado punteros. Esta capacidad en C/C++, aunque poderosa, propicia la
escritura de software defectuoso. Debido a que Java no soporta esta manipulación directa
de punteros, se remueve esta fuente de errores.

Un arreglo es un tipo de objeto que contiene valores llamados elementos. Esto te da un


conveniente contenedor de almacenamiento para un grupo de valores que pueden
modificarse durante el programa, y permite que accedas y cambies los valores según lo
necesites. A diferencia de las variables que son accedidas por un nombre, los elementos
de un arreglo son accedidos por números comenzando por cero. De esta manera puedes
“avanzar” a través del arreglo, accediendo a cada elemento en turno.

Todos los elementos de un arreglo deben ser del mimo tipo. El tipo de elementos de un
arreglo, se decide cuando se declara el arreglo.

Si lo que necesitas es una manera para almacenar un grupo de elementos de tipos


diferentes, puedes usar las clases de colecciones, estas son una nueva característica
en Java 2 y son discutidas en la sección 10.

Declaración sin asignación.


La declaración de un arreglo no asigna almacenamiento alguno, ésta solo anuncia la
intención de crear un arreglo. Una diferencia significativa con la manera en que C/C++
declara un arreglo es que el tamaño no se especifica con el identificador. Por lo tanto lo
siguiente causara un error durante la compilación

int num[5];

El tamaño de un arreglo se da cuando este se crea realmente con el operador new:

int num[];
num = new int[5];

7
Tutorial para el examen de certificación: SCJP 1.2

Creación y Declaración Simultanea.


Lo anterior puede ser compactado en una sola línea así:

int num[] = new int[5];

Además los corchetes pueden ser también colocados después del tipo de dato o después
del nombre del arreglo. Por lo tanto son legales las siguientes declaraciones:

int[] num;
int num[];

Puedes leer esto de la siguiente manera:

• Un arreglo de enteros llamado num


• Un arreglo llamado num de tipo entero.

Arreglos Java VS Arreglos C/C++ .

Una gran diferencia entre java y C/C++ es que en java se conocen de que
tamaño son los arreglos, y el lenguaje proporciona protección para no
sobrepasar los limites del arreglo.

Este comentario es particularmente útil si vienes de un ambiente de programación como


Visual Basic donde no es muy común iniciar el conteo de un arreglo desde 0. También
ayuda a evitar uno de los mas insidiosos errores de C/C++.

Por lo tanto, lo siguiente causará el siguiente error en tiempo de ejecución:


ArrayIndexOutOfBoundException

int[] num = new int [5];


for (int i = 0;i<6;i++){
num[i] = i*2;
}

Para recorrer un arreglo, la manera mas común es a través del campo length de los
arreglos, así:

int [] num = new int[5];


for(int i = 0;i<num.length;i++){
num[i]=i*2;
}

8
javaHispano. Tu comunidad, tu lenguaje.

Los arreglos conocen su tamaño.


Solo en caso de que te hayas saltado la comparación con C/C++ -hecha anteriormente-
los arreglos en Java siempre conocen cual es su tamaño, y este se representa en el
campo length. Así, puedes llenar dinámicamente un arreglo con el código siguiente:

int myarray[] = new int [10];


for(int j=0; j<myarray.length; j++){
myarray[j]=j;
}

Nota que los arreglos tienen el campo length y no el método length(). Cuando
comiences a utilizar Strings usaras el método length, de la siguiente manera:
s.length();

En un arreglo length es un campo (o propiedad) no un método.

Arreglos Java VS Arreglos VB


Los arreglos en Java siempre comienzan desde cero. Los arreglos en VB pueden
comenzar desde 1 si se usa la declaración Option base. En Java no hay equivalente para
el comando redim preserve a través del cual puedes cambiar el tamaño de un arreglo
sin borrar su contenido. Pero por supuesto puedes crear un nuevo arreglo con un
nuevo tamaño y copiar los elementos actuales a ese arreglo y obtener el mismo
resultado.

La declaración de un arreglo puede tener múltiples conjuntos de corchetes (“[]”). Java


formalmente no soporta los arreglos multidimensionales; sin embargo si soporta
arreglos de arreglos; también conocidos como arreglos anidados.

Una diferencia importante entre los arreglos multidimensionales, como en C/C++ y los
arreglos anidados, es que cada arreglo no tiene que ser del mismo tamaño. Si vemos
un arreglo como una matriz, la matriz no tiene que ser una matriz rectángulo .
De acuerdo con la Especificación del Lenguaje Java:

(http://java.sun.com/docs/books/jls/html/10.doc.html#27805)

“El número de corchetes indica la profundidad de un arreglo anidado”

En otros lenguajes esto se conoce como la dimensión de un arreglo. Así podrías


almacenar las coordenadas de un mapa con un arreglo de 2 dimensiones:

int [][];

la 1ª dimensión podría ser la coordenada X y la segunda la coordenada Y.

NT.: En otras palabras; cada arreglo puede tener un tamaño distinto.

9
Tutorial para el examen de certificación: SCJP 1.2

Combinar declaración con inicialización.


En vez de ciclarse a través de un arreglo para llevar a cabo la inicialización, un
arreglo puede ser creado e inicializado a la vez en una sola declaración.

Esto es particularmente recomendable para arreglos pequeños. La siguiente línea


creara un arreglo de enteros y lo llenara con los números 0 hasta el 4.

int k[] = new int[] {0,1,2,3,4};

Observa que en ninguna parte necesitas especificar el número de elementos en el


arreglo. Puedes analizar esto, preguntándote si el siguiente código es correcto:

Int k = new int[5]{0,1,2,3,4}; //¡¡¡ error, no compilara !!!

Puedes crear y llenar arreglos simultáneamente con cualquier tipo de dato, por lo tanto
puedes crear un arreglo de cadenas, de la siguiente manera:

String s[] = new String [] {“Zero”,”One”,”Two”,”Three”,”Four”};

Los elementos de un arreglo pueden ser direccionados como lo harías en C/C++:

String s[] = new String [] {“Zero”,”One”,”Two”,”Three”,”Four”};


System.out.println(s[0]);

Esto mostrará la cadena Zero.

Ejercicio 1)
Crea una clase con un método que simultáneamente cree e inicialize un arreglo de
cadenas. Inicializa el arreglo con cuatro nombres, después muestra el primer nombre
contenido en el arreglo.

Ejercicio 2)
Crea una clase que cree un arreglo de cadenas de 5 elementos llamado Fruit en el
nivel de clase, pero no lo inicializes con cualquier valor. Crea un método llamado
amethod. En amethod inicializa los primeros cuatro elementos con nombres de frutas.
Crea otro método llamado modify y cambia el contenido del primer elemento del
arreglo Fruit para que contenga la cadena “bicycle”. Dentro del método modify
crea un ciclo for que imprima todos los elementos del arreglo.

Solución sugerida para el ejercicio 1.

public class Bevere{


public static void main(String argv[]){
Bevere b = new Bevere();
b.Claines();

10
javaHispano. Tu comunidad, tu lenguaje.

}
public void Claines(){
String[] names= new
String[]{"Peter","John","Balhar","Raj"};
System.out.println(names[0]);

}
}

Nota: La sintaxis para la creación e inicialización simultanea no es evidente y vale la


pena practicarla. Se preguntó por el primer nombre del arreglo para asegurar que no
utilizarás names[1].

Solución Sugerida para el ejercicio 2.

public class Barbourne{


String Fruit[]= new String[5];
public static void main(String argv[]){
Barbourne b = new Barbourne();
b.amethod();
b.modify();
}
public void amethod(){
Fruit[0]="Apple";
Fruit[1]="Orange";
Fruit[2]="Bannana";
Fruit[3]="Mango";
}
public void modify(){
Fruit[0]="Bicycle";
for(int i=0; i< Fruit.length; i++){
System.out.println(Fruit[i]);
}

}
}

Nota: Cuando el ciclo ejecute la salida de elemento final este será null.

11
Tutorial para el examen de certificación: SCJP 1.2

Preguntas.

Pregunta 1)
¿Cómo puedes redimensionar un arreglo con una declaración sencilla manteniendo el
contenido original?

Pregunta 2)
Quieres averiguar el valor del último elemento de un arreglo. Escribiendo el siguiente
Código.¿Qué pasara cuando lo compiles y ejecutes?

public class MyAr{


public static void main(String argv[]){
int[] i = new int[5];
System.out.println(i[5]);
}
}

Pregunta 3)
Quieres hacer un ciclo a través de un arreglo y detenerte cuando llegues al ultimo
elemento. Siendo un buen programador en Java, y olvidando lo que alguna vez conociste
sobre C/C++, sabes que los arreglos contienen información acerca de su tamaño.
¿Cuál de las siguientes sentencias puedes usar?

1)myarray.length();
2)myarray.length;
3)myarray.size
4)myarray.size();

Pregunta 4)
Tu jefe esta complacido por que escribiste el programa Hello World y te ha dado un
aumento. Ahora te encomienda que crees un juego como el TicTacToe(o puntos y cruces
como lo conocí en mi adolescencia). Decides que para eso necesitas un arreglo
multidimensional. ¿Cuál de las siguientes líneas realizan el trabajo?

1) int i=new int[3][3];


2) int[] i=new int[3][3];
3) int[][] i=new int[3][3];
4) int i[3][3]=new int[][];

Pregunta 5)

12
javaHispano. Tu comunidad, tu lenguaje.

Quieres encontrar una manera más elegante para llenar un arreglo que a través de un
ciclo con la sentencia for. ¿Cuál de las siguientes líneas usarías?

1)
myArray{
[1]="One";
[2]="Two";
[3]="Three";
end with

2)String s[5]=new String[]


{"Zero","One","Two","Three","Four"};

3)String s[]=new String[] {"Zero","One","Two","Three","Four"};

4)String s[]=new String[]={"Zero","One","Two","Three","Four"};

Respuestas

Respuesta 1)
No puedes redimensionar un arreglo. Necesitas crear un nuevo arreglo temporal con
un tamaño diferente y llenarlo con el contenido del arreglo original. Java Proporciona
contenedores redimencionables con clases como Vector o uno de los miembros de la
clase collection .

Respuesta 2)
Intentar avanzar mas allá del final del arreglo genera un error en tiempo de ejecución.
Debido a que los arreglos son indexados desde 0, el elemento final será i[4] y no
i[5].

Respuesta 3)
2) myarray.length;

Respuesta 4)
3) int[][] = new int[3][3];

Respuesta 5)
3) String s[] = new String[]{“Zero,”One”,”Two”,”Three”,”Four”};

13
Tutorial para el examen de certificación: SCJP 1.2

Otras Fuentes de este tema:


Este tema es cubierto en el Tutorial de Sun en:
http://java.sun.com/docs/books/tutorial/java/data/arraysAndStrings.html
Richard Baldwin trata este tema en:
http://www.Geocities.com/Athens/Acropolis/3797/Java028.htm
Jyothi Krishnan en:
http://www.geocities.com/SiliconValley/Network/3693/obj_sec1.html#obj1

Bruce Eckel Thinking In Java


Capítulo 8

14
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 2.
Declarar clases, clases internas, métodos, variables de instancia estáticas, variables y
variables automáticas(métodos locales), haciendo un uso apropiado de todos los
modificadores permitidos (como son: public, final, static, abstract, y
demás). Conocer importancia de cada uno de estos modificadores ya sea solos o en
combinación

Comentario sobre este objetivo

Encuentro un poco molesto que en el objetivo se use la frase “y demás”.


Supongo que esto significa que debes estar consciente de los modificadores:

native
transient
synchronized
volatile

Comparando las clases de C++/VB con las de Java.


Debido a que Java fue diseñado para facilitar que programadores C++ lo aprendieran,
este tiene muchas similitudes en la manera en que ambos lenguajes trabajan con las
clases. Ambos lenguajes tienen herencia, polimorfismo, y ocultamiento de datos usando
modificadores de visibilidad. Algunas de sus diferencias fueron hechas para hacer de
Java un lenguaje más fácil de aprender y usar.

El lenguaje C++ implementa la herencia múltiple y así una clase puede tener más de un
padre (o clase base) Java únicamente permite la herencia simple, es decir, las clases
pueden tener únicamente un padre. Para sobreponer esta limitación, Java tiene una
característica llamada: Interfaces, a la cual los diseñadores del lenguaje le decidieron dar
algunas de las ventajas de la herencia múltiple, pero sin las desventajas. Todas las clases
en Java son descendientes de una gran clase antecesora llamada Object.

El rol de las clases en Java


Las clases son el corazón de Java, todo el código en Java ocurre dentro de una clase. No
hay un concepto de código llano y de posición libre. Hasta la más sencilla aplicación
HelloWorld involucra la creación de una clase. Para indicar que una clase desciende de
otra clase se usa la palabra clave extends. Si no se usa extends, la clase descenderá
de la clase Object lo cual proporciona a la clase creada, algunas funciones básicas
incluyendo la habilidad para mostrar su nombre y algunas de las capacidades requeridas
en los Threads.

15
Tutorial para el examen de certificación: SCJP 1.2

La clase más sencilla.


Los requerimientos mínimos para definir una clase son: la palabra clave class, el
nombre de la clase y las llaves de apertura y cerradura. Entonces:

class classname {}

es una definición sintacticamente correcta para una clase, pero no es una clase
particularmente útil (sorprendentemente, me he encontrado definiendo clases como esta,
cuando creo ejemplos para ilustrar la herencia)

Normalmente una clase también incluirá un especificador de acceso antes de la palabra


clave class y por supuesto, el cuerpo de la clase entre las llaves. Así, lo siguiente es una
plantilla mas sensata para definir una clase:

public class classmane{


// el cuerpo de la clase va acá
}

Creando una clase sencilla- HelloWorld


Este es un sencillo programa HelloWorld que mostrar: la cadena “hello world” en la
pantalla.

public class HelloWorld{


public static void main(String argv[]){
System.out.println("hello world");
}
}//Fin de la Definición de la clase

La palabra clave public es un modificador de visibilidad que indica que la clase deberá
ser visible para cualquier otra clase. Solo una clase por archivo puede ser declarada
publica. Si declaras mas de una clase en un archivo como publica, ocurrirá un error en
tiempo de ejecución. Observa que Java es sensible a mayúsculas en todos los aspectos. El
archivo que contenga esta clase deberá llamarse HelloWorld.java

La palabra clave class indica que una clase comienza a ser definida y HelloWorld es
el nombre de la clase. Observa que la llave de cierre que finaliza la definición de la clase
no involucra un punto y coma de cerradura. El comentario:

//Fin de la Definición de la clase

Usa el estilo de comentario de una sola línea que esta disponible en C/C++. Java también
comprende los comentarios multilíneas de la forma /* */.

La magia del nombre main

16
javaHispano. Tu comunidad, tu lenguaje.

Dando a un método la siguiente forma, esté obtiene cierta significancia (o magia) cuando
indica a Java que es aquí en donde el programa debe empezar a ejecutarse. (similar al
main del lenguaje C).

public static void main(String argv[]){

Esta línea indica que esta definiéndose un método llamado main, y que toma como
parámetros (o argumentos) a un arreglo de cadenas. Este método es publico, es decir es
visible desde cualquier parte de la clase. La palabra clave static indica que este método
puede ejecutarse sin crear una instancia de la clase. Si eso no significa nada para ti, no te
preocupes, en su momento se cubrirán con detalle los métodos estáticos (static) en otra
parte de este tutorial. La palabra clave void indica el tipo de dato retornado por el
método cuando se llama. Usar void indica que ningún valor será retornado.

El parámetro del método main:

String argv[]

Indica que el método toma un arreglo de tipo String. Los corchetes indican –como ya
vimos- un arreglo. Observa que el tipo de dato String comienza con una “S”
mayúscula. Esto es importante ya que Java es totalmente sensible a las mayúsculas. Sin
estas exactitudes, la Maquina virtual de Java (JVM) no reconocerá el método como el
lugar en donde se debe comenzar la ejecución del programa.

Creando una instancia de una Clase


La aplicación HelloWorld, como describí anteriormente, es útil para ilustrar la más
sencilla de las aplicaciones que puedes crear. Pero le falta mostrar uno de los elementos
más cruciales al usar las clases, la palabra clave new.
La cual indica la creación de una nueva instancia de la clase. En la aplicación
HelloWorld esto no era necesario ya que el único método que se llamó era
System.out.println que es un método estático y no requiere la creación de una clase que
utilice la palabra new. Los métodos estáticos pueden acceder solo a variables estáticas, de
las que sólo puede existir una instancia por la clase. La aplicación de HelloWorld puede
modificarse ligeramente para ilustrar la creación de una nueva instancia de una clase.

public class HelloWorld2{


public static void main(String argv[]){
HelloWorld2 hw = new HelloWorld2();
hw.amethod();
}

public void amethod(){


System.out.println("Hello world");
}
}

17
Tutorial para el examen de certificación: SCJP 1.2

Este código crea una nueva instancia de si mismo en la línea:

HelloWorld2 hw = new HelloWorld2();

Esta sintaxis para crear una nueva instancia de una clase es básica para el uso de clases.
Observa cómo el nombre de la clase aparece dos veces. La primera vez indica el tipo de
dato de la referencia a la clase. Esta necesidad no es la misma que el tipo actual de la
clase puesto que ésta se indica después de usar la palabra clave new. El nombre de esta
instancia de la clase es hw. Éste simplemente es un nombre escogido para una variable.
Este es un nombramiento convencional (es decir, utilizando la convención para escritura
de código Java)ya que una instancia de una clase empieza con una letra minúscula,
considerando que la definición de una clase empieza con una letra mayúscula.

El paréntesis vacío para el nombre de la clase HelloWorld() indica que la clase está
creándose sin algún parámetro en su constructor. Si estuvieras creando una instancia de
una clase que se inicializa con un valor o un arreglo como la clase Label o Button el
paréntesis contendría uno o mas valores de inicialización.

Creando Métodos.
Como ilustro en el último ejemplo HelloWorld2, un método en Java es similar a una
función en C/C++ y a una función o sub función en Visual Basic. El método llamado
amethod en este ejemplo se declara como:

public

que indica que puede accederse desde cualquier parte. Retorna el tipo:

void

Indicando que ningún valor será retornado. Y los paréntesis vacíos indican que no toma
parámetros.

El mismo método se podría haber definido de estas maneras alternativas:

private void amethod(String s)


private void amethod(int i, String s)
protected void amethod(int i)

Estos ejemplos ilustran algunas otras firmas típicas de declaración de métodos. El uso de
las palabras clave private y protected se cubrirá en otro apartado.

La diferencia entre los métodos de Java y métodos en lenguajes no orientados a objetos


como C es que los métodos pertenecen a una clase. Esto significa que se llaman usando la
anotación del punto que indica la instancia de la clase a la que el método pertenece (Los
métodos estáticos son una excepción a esto pero no te preocupes sobre ellos por el
momento)

18
javaHispano. Tu comunidad, tu lenguaje.

Así en HelloWorld2 el método amethod se llamo así:

HelloWorld hw = new HelloWorld();


hw.amethod();

Si se hubieran creado otras instancias de la clase HelloWorld el método podría llamarse


desde cada instancia de la clase. Cada instancia de la clase tendría acceso a sus propias
variables. Así lo siguiente involucraría la llamada al código del método amethod de las
diferentes instancias de la clase.

HelloWorld hw = new HelloWorld();


HelloWorld hw2 = new HelloWorld();
hw.amethod();
hw2.amethod();

Las dos instancias de la clase: hw y hw2 podrían tener acceso a variables diferentes.

Variables Automáticas

Las variables automáticas son las variables de los métodos. Estas entran en el alcance del
programa cuando empieza a ejecutarse el código del método y dejan de existir una vez
que el método deja de ejecutarse. Son sólo visibles dentro del método y son útiles
principalmente para la manipulación de datos temporales. Si quieres que un valor
permanezca entre las llamadas de un método entonces la variable necesita ser creada al
nivel de la clase.

Una variable automática será la "sombra" de una variable de nivel de clase.

Así el código siguiente mostrará 99 y no 10:

public class Shad{


public int iShad=10;
public static void main(String argv[]){
Shad s = new Shad();
s.amethod();
}//fin de main
public void amethod(){
int iShad=99;
System.out.println(iShad);
}//fin de amethod
}

19
Tutorial para el examen de certificación: SCJP 1.2

Modificadores y Encapsulamiento.

Los modificadores de visibilidad son parte del mecanismo de encapsulamiento


para Java. El encapsulamiento permite la separación de la interfase y la
implementación de métodos.

A menudo estos métodos son para recuperar y actualizar los valores de una variable local
privada. Son conocidos como métodos accessor (acceder o obtener el valor de la
variable) y mutator (modificar el contenido de una variable). La convención para
nombrar a estos métodos es setFoo para modificar y getFoo para obtener el contenido
de una variable. Así si estuvieras almacenado una variable llamada age deberías hacerla
privada y actualizarla con:

setAge

y recuperar su valor con:

getAge

Usando código para modificar variables; el valor de la variable también puede


verificarse, por ejemplo: si el valor esta dentro de un rango en particular o revisar si es un
numero positivo.

Private

Las variables privadas son sólo visibles dentro de la misma clase donde se crean. Esto
significa que NO son visibles dentro de las subclases. Esto permite que la variable sea
aislada de ser modificada por cualquier método, exceptuando aquellos en la clase actual.
Como se dijo anteriormente, esto es útil para separar la interfase de la implementación.

class Base{
private int iEnc=10;
public void setEnc(int iEncVal){
if(iEncVal < 1000){
iEnc=iEncVal;
}else
System.out.println("Enc value must be less than 1000");
//Or Perhaps thow an exception
}//End if
}
public class Enc{
public static void main(String argv[]){
Base b = new Base();
b.setEnc(1001);
}//End of main
}

20
javaHispano. Tu comunidad, tu lenguaje.

Public

El modificador public puede aplicarse a una variable (campo) o una clase. Es


probablemente el primer modificador que conociste aprendiendo Java. Si revisas el
código para HelloWorld.Java, que se programó en un principio, la clase se declaró como:

public class HelloWorld

Esto es porque para iniciar el método mágico la JVM, sólo revisa en una clase declarada
como publica:

public static void main(String argv[])

Una clase pública tiene alcance global, y una instancia puede crearse desde cualquier
parte dentro o fuera de un programa. Únicamente una clase en un archivo puede definirse
con la palabra clave public. Si defines más de una clase en un archivo con la palabra
clave public el compilador generará un error

class Base {
public int iNoEnc=77;
}
public class NoEnc{
public static void main(String argv[]){
Base b = new Base();
b.iNoEnc=2;
System.out.println(b.iNoEnc);
}//End of main
}

Observa que generalmente ésta no es la manera sugerida ya que no permite ninguna


separación entre la interfase y implementación del código. Si decidieras cambiar el tipo
de dato de iNoEnc, tendrías que modificar la implementación de cada parte del código
externo que lo modifica.

Protected

El modificador protected es una pequeña rareza. Una variable protegida es visible


dentro de una clase, en una subclase, y en el mismo paquete, pero no en otra parte. La
cualidad de ser visible dentro del mismo paquete puede darle más visibilidad de la que
podrías sospechar. Cualquier clase que esté en el mismo directorio se considera que está
en el paquete predefinido, y así las clases protegidas serán visibles. Esto significa que una
variable protegida tiene más visibilidad que una variable definida sin modificador de
acceso.

21
Tutorial para el examen de certificación: SCJP 1.2

Se dice que una variable definida sin modificador de acceso tiene visibilidad predefinida.
La visibilidad predefinida significa que una variable puede verse dentro de la clase, y
desde otra parte dentro del mismo paquete, pero no desde una subclase que no esté en el
mismo paquete.

Static

Static no es directamente un modificador de visibilidad, aunque en la práctica tiene


este efecto. El modificador static puede aplicarse a una clase, a un método y una
variable. Marcando una variable como estática se indica que sólo una copia de esa
variable existirá por clase. Esto está en contraste con las variables normales donde por
ejemplo una copia de una variable integer pertenece a cada instancia de una clase. Así
en el ejemplo siguiente existirán tres instancias de la variable integer iMyVal y cada
instancia podra contener un valor diferente.

class MyClass{
public int iMyVal=0;
}
public class NonStat{
public static void main(String argv[]){
MyClass m1 = new MyClass();
m1.iMyVal=1;
MyClass m2 = new MyClass();
m2.iMyVal=2;
MyClass m3 = new MyClass();
m3.iMyVal=99;
//Esto mostrará 1. Ya que cada instancia de
// la clase tiene su propia copia de MyVal
System.out.println(m1.iMyVal);
}//End of main
}

El Ejemplo siguiente muestra que pasa cuando tienes múltiples instancias de una clase
que contiene una variable estática, en este ejemplo la variable estática es iMyEval.

class MyClass{
public static int iMyVal=0;
}//End of MyClass
public class Stat{
public static void main(String argv[]){
MyClass m1 = new MyClass();
m1.iMyVal=0;
MyClass m2 = new MyClass();
m2.iMyVal=1;
MyClass m3 = new MyClass();
m2.iMyVal=99;
//Debido a que iMyVal es static,
//hay sólo una copia de él no importa

22
javaHispano. Tu comunidad, tu lenguaje.

//cuantas instancias de la clase se creen.


//Este código mostrará el valor de 99
System.out.println(m1.iMyVal);
}//End of main
}

Ten presente que no puedes acceder a variables no estáticas desde dentro de un método
estático. Así lo siguiente causará un error en tiempo de compilación.

public class St{


int i;
public static void main(String argv[]){
i = i + 2;//Causará un error al compilar
}
}

Un método estático no puede ser sobreescrito para ser no estático en una clase
hija.

Un método estático no puede ser sobreescrito para ser no estático en una clase hija. No
hay ninguna regla similar con referencia a la sobrecarga. El código siguiente causará un
error cuando intentes sobreescribir el método amethod de la clase Base para ser no
estático.

class Base{
public static void amethod(){
}
}
public class Grimley extends Base{
public void amethod(){}//Causa un error en tiempo de
compilación
}

El compilador Jikes de IBM produce el siguiente error:

Found 1 semantic error compiling "Grimley.java":


6. public void amethod(){}
<------->
*** Error: The instance method "void amethod();"
cannot override the static method "void amethod();"
declared in type "Base"

Native

El modificador native sólo se usa para los métodos e indica que el cuerpo del código
esta escrito en un lenguaje que no es Java como C y C++. Se escriben a menudo métodos

23
Tutorial para el examen de certificación: SCJP 1.2

nativos para propósitos específicos de la plataforma como acceder a algún elemento de


hardware del cual la Maquina Virtual de Java no este consciente. Otra razón es utilizarlo
donde se requiere mayor desempeño.

Un método nativo termina con punto y coma en lugar de un bloque del código. Así lo
siguiente llamaría una rutina externa, escrita quizás en C++,

public native fastcalc();

Abstract

Es fácil pasar por alto el modificador abstract y perderse algunas de sus


implicaciones. Es la clase de modificador que a los examinadores les gusta para hacer
preguntas complicadas.

El modificador abstracto puede aplicarse a las clases y a los métodos. Cuando se


aplica a un método indica que éste no tendrá cuerpo y el código sólo puede ejecutarse
cuando se implemente en una clase hija. Sin embargo hay algunas restricciones sobre
cuando y donde puedes tener métodos abstractos y reglas sobre las clases que los
contienen. Cuando se aplica a una clase, indica que la clase tiene un por lo menos método
abstracto.

Si una clase tiene algún método abstracto esta debe ser asimismo declarada
abstracta .

Sin embargo, no te distraigas pensado que una clase abstracta no puede tener métodos
no abstractos. Cualquier clase que descienda de una clase abstracta debe implementar los
métodos abstractos de la clase base o debe declararlos abstractos ella misma. ¿Tienden
estas reglas a generar la pregunta por qué querrías crear métodos abstractos?

Los métodos abstractos son principalmente beneficiosos a los diseñadores de clases.


Ofrecen al diseño de una clase una manera de crear un prototipo para métodos que han de
ser implementados, pero la implementación real queda a las personas que usan las clases
después. Aquí hay un ejemplo de una clase abstracta con un método abstracto. De nuevo
nota que la propia clase se declara abstracta, de otra manera habría ocurrido un error en
tiempo de compilación.

La siguiente clase es abstracta y se compilará sin problemas:

public abstract class abstr{


public static void main(String argv[]){
System.out.println("hello in the abstract");
}
public abstract int amethod();

24
javaHispano. Tu comunidad, tu lenguaje.

Final

El modificador final indica que un método no puede ser heredado. Otra manera de
entender esto es que una clase final no puede ser una clase padre. Cualquier método en
una clase final es automáticamente final. Esto puede ser útil si no quieres que otros
programadores "hechen a perder tu código". Otro beneficio es la eficacia puesto que el
compilador tiene menos trabajo al trabajar con un método final. Esto se cubre mejor en el
Volumen 1 de Core Java.

El código siguiente ilustra el uso del modificador final en una clase. Este código mostrará
la cadena "amethod":

final class Base{


public void amethod(){
System.out.println("amethod");
}
}
public class Fin{
public static void main(String argv[]){
Base b = new Base();
b.amethod();
}
}

Shynchronized

La palabra clave synchonized se usa para prevenir que más de un thread acceda a un
bloque de código a la vez. Ve la sección 7 sobre threads para entender más cómo
funciona esto.

Transient

La palabra clave transient es uno de los modificadores frecuentemente menos usados.


Indica que una variable no debe escribirse fuera cuando una clase es serializada.

Volatile

Probablemente no conseguirás realizar alguna pregunta sobre la palabra clave volatile. Lo


peor que conseguirás es reconocer que realmente es un palabra clave de Java. Según
Barry Boone:

"le dice al compilador que una variable puede cambiar asincrónicamente debido a los
threads"

25
Tutorial para el examen de certificación: SCJP 1.2

Acepta que es parte del lenguaje y entonces mejor preocúpate por otras cosas.

Usando modificadores en combinación


Los modificadores de visibilidad no pueden usarse en combinación, así una variable no
puede ser privada y pública, pública y protegida o protegido y privada. Puedes tener
combinaciones de los modificadores de visibilidad y los modificadores mencionados, por
supuesto, en mi lista "y demás".

• native
• transient
• synchronized
• volatile

Así puedes tener un método public static native.

Donde pueden usarse los modificadores


Modificador Método Variable clase
public si si si
private si si si(anidable)
protected si si si(anidable)
abstract si no si
final si si si
transient no si no
native si no no
volatile no si no

Ejercicio 1)
Crea un archivo llamado Whitley.java. En este archivo define una clase llamada Base
con un método abstracto llamado lamprey que retorne un valor de tipo int. En el
mismo archivo crea una clase llamada Whitley que descienda de la clase Base.
Proporciona a la clase Whithley un método llamado lamprey con el código necesario
para mostrar en pantalla la cadena “lamprey”.

Crea un método nativo para la clase llamado mynative. Ahora compila y ejecuta el
código.

Ejercicio 2)

26
javaHispano. Tu comunidad, tu lenguaje.

Crea una clase publica llamada Malvern. Crea una clase interna y privada llamada
Great que tenga un método llamado show de la forma public void. Haz que este
método muestre en pantalla la cadena “Show”. Proporciona a la clase Malvern un
método publico llamado go que cree una instancia de Great y después de ser
instanciada llame al método show. En el método main de la clase Malvern crea una
instancia de sí misma. Haz que esta instancia llame al método go. Compila y ejecuta el
código.

Solución sugerida para el ejercicio 1.

abstract class Base{


abstract int lamprey();
}
public class Whitley extends Base{
public static void main(String argv[]){

}
public int lamprey(){
System.out.println("lamprey");
return 99;
}
native public void mynative();
}

Solución sugerida para el ejercicio 2.

public class Malvern{


public static void main(String argv[]){
Malvern m = new Malvern();
m.go();
}
public void go(){
Great g = new Great();
g.show();
}
private class Great{
public void show(){
System.out.println("Show");
}
}
}

27
Tutorial para el examen de certificación: SCJP 1.2

Preguntas.

Pregunta 1)
¿Qué pasará cuando intentes compilar y ejecutar este código?

abstract class Base{


abstract public void myfunc();
public void another(){
System.out.println("Another method");
}
}
public class Abs extends Base{
public static void main(String argv[]){
Abs a = new Abs();
a.amethod();
}
public void myfunc(){
System.out.println("My func");
}
public void amethod(){
myfunc();

}
}

1) El código se compilará y se ejecutará, mostrando la cadena “My func”


2) El código indicara que la clase Base no tiene métodos abstractos.
3) El código se compilara pero indicará un error en tiempo de ejecución (run time
error): la clase base no tiene métodos abstractos
4) El compilador indicara que el método myfunc en la clase Base no tiene cuerpo.

Pregunta 2)
¿Qué pasara cuando intentes compilar y ejecutar este código?

public class MyMain{


public static void main(String argv){
System.out.println("Hello cruel world");
}
}

28
javaHispano. Tu comunidad, tu lenguaje.

1) El compilador indicara que main es una palabra reservada y no puede ser usada
para nombrar una clase.
2) El código se compilará y cuando se ejecute mostrara en pantalla la cadena
“Hello cruel world”.
3) El código se compilara pero indicará un error en tiempo de ejecución: el
constructor no esta definido.
4) El código se compilara pero indicara que la función main no esta definida
correctamente.

Pregunta 3)
¿De los siguientes cuales son modificadores de Java?

1) public
2) private
3) friendly
4) transient

Pregunta 4)
¿Qué pasará cuando intentes compilar y ejecutar este código?

class Base{
abstract public void myfunc();
public void another(){
System.out.println("Another method");
}
}
public class Abs extends Base{
public static void main(String argv[]){
Abs a = new Abs();
a.amethod();
}
public void myfunc(){
System.out.println("My func");
}
public void amethod(){
myfunc();

}
}

1) El código se compilará y se ejecutará, mostrando la cadena “My func”


2) El compilador indicará que la clase Base no esta declarada como abstracta.
3) El código se compilará pero indicará un error en tiempo de ejecución: la clase
base no tiene métodos abstractos
4) El compilador indicará que el método myfunc en la clase Base no tiene cuerpo.

29
Tutorial para el examen de certificación: SCJP 1.2

Pregunta 5)
¿Para que defines un método como nativo?

1) Para conseguir acceder a Hardware desconocido por Java


2) Para definir un nuevo tipo de dato como un entero sin signo.
3) Para escribir código optimizado para el mejor desempeño en un lenguaje como
C/C++.
4) Para superar la limitación del alcance privado de un método

Pregunta 6)
¿Qué pasará cuando intentes compilar y ejecutar este código?

class Base{
public final void amethod(){
System.out.println("amethod");
}
}
public class Fin extends Base{
public static void main(String argv[]){
Base b = new Base();
b.amethod();
}
}

1) Un error en tiempo de compilación indicando que una clase con algún método
final debe ser declarado final por si misma.
2) Un error en tiempo de compilación indicará que no puedes heredar de una clase
con métodos final
3) Un error en tiempo de ejecución indicando que Base no esta definida como
final
4) Éxito en la compilación y al ejecutarse mostrará en pantalla “amethod”.

Pregunta 7)
¿Qué pasará cuando intentes compilar y ejecutar este código?

public class Mod{


public static void main(String argv[]){
}
public static native void amethod();
}

1) Error en la compilación: método nativo no puede ser static.

30
javaHispano. Tu comunidad, tu lenguaje.

2) Error en la compilación: método nativo debe retornar algún valor.


3) Compilación correcta pero habrá un error en tiempo de ejecución a menos que
hallas hecho código para hacer útil el método nativo.
4) Compilación y ejecución sin error.

Pregunta 8)
¿Qué pasará cuando intentes compilar y ejecutar este código?

private class Base{}


public class Vis{
transient int iVal;
public static void main(String elephant[]){
}
}

1) Un error en tiempo compilación: la clase Base no puede ser privada.


2) Un error en tiempo de compilación indicando que un entero no puede ser
transient
3) Un error en tiempo de compilación indicando que transient no es un tipo de
dato.
4) Un error en tiempo de compilación indicando que el método main esta deformado

Pregunta 9)
¿Qué pasara cuando intentes compilar y ejecutar estos dos archivos en el mismo
directorio?

//Archivo P1.java
package MyPackage;
class P1{
void afancymethod(){
System.out.println("What a fancy method");
}
}
//Archivo P2.java
public class P2 extends P1{
afancymethod();
}

1) Ambos se compilarán y P2 mostrará en pantalla “Wath a fancy method”


cuando se ejecute.
2) No se compilará ninguno.
3) Ambos se compilarán pero P2 tendrá un error en tiempo de ejecución.
4) P1 se compilará limpiamente pero P2 tendrá un error al compilarse.

31
Tutorial para el examen de certificación: SCJP 1.2

Pregunta 10)
¿Cuáles de las declaraciones siguientes son legales?

1) public protected amethod(int i)


2) public void amethod(int i)
3) public void amethod(void)
4) void public amethod(int i)

Respuestas.

Respuesta 1)
1) El código se compilara y se ejecutara, mostrando la cadena “My func”

Una clase abstracta puede tener métodos no abstractos, pero cualquier clase que
descienda de ella, debe implementar todos los métodos abstractos.

Respuesta 2)

1) El código se compilara pero indicara que la función main no esta definida


correctamente.

La función main recibe un String en lugar de un arreglo de String que es lo


correcto.

Respuesta 3)

1) public
2) private
4) transient

Aunque algunos textos usan la palabra “friendly” cuando tratan el tema de visibilidad,
esta no es una palabra reservada de Java. Toma en cuenta que será casi seguro que el
examen contenga problemas que te pidan que identifiques palabras claves de Java en una
lista.

Respuesta 4)

2) El compilador indicara que la clase Base no esta declarada como abstracta.

El mensaje de error utilizando JDK 1.1. es:

Abs.java:1: class Base must be declared abstract.


It does not define void myfunc
() from class Base.
class Base{

32
javaHispano. Tu comunidad, tu lenguaje.

^
1 error

Respuesta 5)

1) Para conseguir acceder a hardware desconocido por Java


3) Para escribir código optimizado para el mejor desempeño en un lenguaje como C/C++

Aunque la creación de código “PURE JAVA”es altamente conveniente, particularmente


para permitir la independencia de plataforma, no debe de tomarse como una religión, y
hay ocasiones en que se requiere el código nativo.

Respuesta 6)

4)Éxito en la compilación y al ejecutarse mostrará en pantalla “amethod”.

Este código llama a una versión de amethod de la clase Base. Si intentas implementar
una versión sustituida del método en la clase Fin conseguirás un error en tiempo de
compilación.

Respuesta 7)

4)Compilación y ejecución sin error.

Esta línea no es una llamada a un método nativo –solo se esta declarando- y por lo tanto
no ocurre un error en la ejecución.

Respuesta 8)

1)Un error en tiempo compilación: la clase Base no puede ser privada.

Una clase de un nivel alto, al igual que una clase base, no puede ser declarada como
privada

Respuesta 9)

4)P1 se compilará limpiamente pero P2 tendrá un error al compilarse.

Aunque P2 esta en el mismo directorio que P1, debido a que P1 fue declarado como parte
de un paquete, P1 no esta visible para P2.

Respuesta 10)

2)public void amethod(int i)

Si pensaste que la opción 3 es legal utilizando como parámetro el argumento void, debes
quitarte un poco de C/C++ de la cabeza.

33
Tutorial para el examen de certificación: SCJP 1.2

La opción 4 no es legal porque el tipo de datos debe aparecer después de cualquier


especificador de acceso.

Otras Fuentes para este tema.


Este tema es cubierto en el tutorial de Sun como Modificadores de clases:
http://java.sun.com/docs/books/tutorial/reflect/class/getModifiers.html
Controlando el acceso a los miembros de una clase:
http://java.sun.com/docs/books/tutorial/java/javaOO/accesscontrol.html

Richard Baldwin Cubre este tema en


http://www.Geocities.com/Athens/Acropolis/3797/Java040.htm

Jyothi Krishnan en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec1.html#obj2

Bruce Eckel Thinking in Java


Chapter 5 (aunque tiene la cabeza llena de C++ e insiste en incluir el modificador “friendly”)

34
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 3.

Para una clase dada, determinar si se debe crear un constructor predefinido, y si ese es el
caso, declarar el prototipo de ese constructor.

Nota de este objetivo

Éste es un objetivo pequeño pero oportuno, que se concentra en un aspecto fácilmente


pasado por alto en Java

¿Qué es un constructor?

Necesitas comprender el concepto de constructor para entender este objetivo.


Brevemente, es el código que se ejecuta automáticamente cuando se crea la clase. Los
constructores a menudo se usan para iniciar valores en la clase. Los constructores tienen
el mismo nombre de a clase y no retornan ningún valor. En el examen puedes encontar
preguntas sobre métodos que tengan el mismo nombre de la clase pero que retornan algún
tipo, como int o String. Ten cuidado y asegúrate que cualquier método que asumas
que es un constructor no debe retornar algún tipo de dato.

Aquí hay un ejemplo de una clase con un constructor que muestra "Greetings from
Crowle" cuando se crea una instancia de la clase.

public class Crowle{


public static void main(String argv[]){
Crowle c = new Crowle();
}
Crowle(){
System.out.println("Greetings from Crowle");
}
}

¿Cuándo proporciona Java el constructor predefinido?

Si no defines específicamente algún constructor, el compilador inserta “fuera de escena”


un constructor invisible con cero parámetros, frecuentemente esto solo es de importancia
teórica, pero lo verdaderamente importante es que solo recibes el constructor predefinido
con cero parámetros si no creas algún constructor propio.

35
Tutorial para el examen de certificación: SCJP 1.2

Si creas tus propios constructores, Java ya no te proporciona el constructor


predefinido con cero parámetros. Así que tienes que especificarlo.

En cuanto creas algún constructor propio, pierdes el constructor predefinido con cero
parámetros. Si intentas crear una instancia de una clase, sin pasarle algún parámetro
(invocando la clase con el constructor con cero parámetros), obtendrás un error. Así,
cuando crees algún constructor para una clase necesitarás crear el constructor con cero
parámetros. Esta es una de las razones por las que generadores de código como
Borland/Inprise o JBuilder, crean un constructor con cero parámetros cuando generan el
esqueleto de una clase.

El ejemplo siguiente muestra código que no compilará. Cuando el compilador verifica la


creación de la instancia c de la clase Base, inserta una llamada al constructor con cero
parámetros. Debido a que la clase Base tiene un constructor que recibe un entero, el
constructor con cero parámetros ya no esta disponible. Esto se puede arreglar creando en
la clase Base un constructor con cero parámetros que “no haga nada”.

//Advertencia: no se compilará
class Base{
Base(int i){
System.out.println("single int constructor");
}
}

public class Cons {


public static void main(String argv[]){
Base c = new Base();
}
}

//Esto si se compilará
class Base{
Base(int i){
System.out.println("single int constructor");
}
Base(){}
}

public class Cons {


public static void main(String argv[]){
Base c = new Base();
}
}

36
javaHispano. Tu comunidad, tu lenguaje.

El prototipo del constructor predefinido

El objetivo te pide que estes consciente del prototipo del constructor predefinido.
Naturalmente no debe tener ningún parámetro. La predefinición más evidente es no tener
ningún especificador de alcance, pero puedes definir un constructor como público o
protegido.

Los constructores no pueden ser nativos, abstractos, estáticos, sincronizados ni finales.

Ese pedazo de información se derivó directamente de un mensaje de error del


compilador. Parece que la calidad de los mensajes de error están mejorando con las
nuevas versiones de Java. He oído que el nuevo compilador de Java de IBM tiene un
buen informador de errores. Podrían aconsejarte que tuvieras disponible más de una
versión del compilador de Java para verificar tu código y buscar los errores.

Ejercicios

Ejercicio 1)
Crea una clase llamada Salwarpe con un método llamado hello que muestre la cadena
“hello”. En el método main de la clase crea una instancia de sí misma llamada s1 y
llama al método hello desde la instancia. Compila y ejecuta el programa para que
puedas ver el resultado.

Ejercicio 2)
Usando todavía el archivo Salwarpe.java comenta las líneas que crean la instancia y
llaman al método hello. Crea un constructor publico para la clase que tome un
parámetro entero y muestre el valor del entero. Crea una instancia de la clase llamada s2
proporciónale el valor de 99 al constructor. Compila y ejecuta el programa para que
puedas ver mostrado el resultado.

Ejercicio 3)
Descomenta las líneas que crean la instancia s1 y modifica el programa para que
compile, ejecute y muestre ambos la cadena Hello y el numero 99.

Solución sugerida para el ejercicio 1.

public class Salwarpe {


public static void main(String argv[]){
Salwarpe s1 = new Salwarpe();
s1.hello();
}
public void hello(){
System.out.println("Hello");
}

37
Tutorial para el examen de certificación: SCJP 1.2

Solución sugerida para el ejercicio 2.

public class Salwarpe {


public static void main(String argv[]){
//Salwarpe s1 = new Salwarpe();
//s1.hello();
Salwarpe s2 = new Salwarpe(99);
}
public void hello(){
System.out.println("Hello");
}
public Salwarpe(int i){
System.out.println(99);
}
}

Solución sugerida para el ejercicio 3.

public class Salwarpe {


public static void main(String argv[]){
Salwarpe s1 = new Salwarpe();
s1.hello();
Salwarpe s2 = new Salwarpe(99);
}
public void hello(){
System.out.println("Hello");
}
public Salwarpe(int i){
System.out.println(99);
}
public Salwarpe(){}
}

Observa como fue necesario crear el constructor con cero parámetros para este último
ejercicio. Una vez que has creado algún constructor para una clase, Java ya no te
proporciona “tras escena” el constructor con cero parámetros que estaba disponible en el
ejercicio 1.

38
javaHispano. Tu comunidad, tu lenguaje.

Preguntas

Pregunta 1)
Dada la siguiente definición de clase:

class Base{
Base(int i){}

}
class DefCon extends Base{
DefCon(int i){
//XX
}
}

¿Cuál se las líneas siguientes será individualmente valida si se sustituye por la línea
marcada con //XX?

1) super();
2) this();
3) this(99);
4)super(99);

Pregunta 2)
Dada la siguiente definición de clase:

public class Crowle{


public static void main(String argv[]){
Crowle c = new Crowle();
}
Crowle(){
System.out.println("Greetings from Crowle");
}
}

¿Cuál es el tipo de dato retornado por el constructor?

1) null
2) integer
3) String
4) no es retornado algún tipo de dato

Pregunta 3)

¿Qué pasara cuando intentes compilar y ejecutar el siguiente código?

39
Tutorial para el examen de certificación: SCJP 1.2

public class Crowle{


public static void main(String argv[]){
Crowle c = new Crowle();
}
void Crowle(){
System.out.println("Greetings from Crowle");
}
}

1)Se compilara y mostrará la cadena “Greetings from Crowle”.


2)Error en tiempo de compilación: un constructor no puede retornar un tipo de dato.
3)Se compilara y mostrará la cadena “void”.
4)Se compilara y no mostrará nada al ejecutarse.

Pregunta 4)
¿Qué pasara cuando intentes compilar y ejecutar el siguiente código?

class Base{
Base(int i){
System.out.println("Base");
}

}
class Severn extends Base{
public static void main(String argv[]){
Severn s = new Severn();
}
void Severn(){
System.out.println("Severn");
}
}

1)Se compilará al ejecutarse y mostrará la cadena “Seven”.


2)Error en tiempo de compilación.
3)Se compilará y no mostrará nada al ejecutase
4)Se compilará y mostrará la cadena “Base”

Pregunta 5)

¿Cuáles de las siguientes declaraciones son verdaderas?

1)El constructor predefinido retorna un tipo void.


2)El constructor predefinido toma como parámetro un valor tipo void.
3)El constructor predefinido no toma parámetros.

40
javaHispano. Tu comunidad, tu lenguaje.

4)El constructor predefinido no se crea si la clase contiene algún constructor propio

Respuestas

Respuesta 1)

4)super (99)

Debido a que la clase Base tiene definido un constructor, el compilador no insertará el


constructor predefinido con cero parámetros. Por consiguiente, llamar a super() causará
un error. Una llamada a this() es un intento de llamar a un constructor con cero
parámetros inexistente en la clase actual. La llamada a this(99) causará una referencia
circular y causará un error en tiempo de compilación.

Respuesta 2)

4) no es retornado algún tipo de dato

Debe ser bastante obvio de que ningún tipo de dato se retorna, así como por definición
los constructores no tienen tipos de datos

Respuesta 3)

4)Se compilara y no mostrará nada al ejecutarse.

Debido a que el método Crowle retorna un tipo de dato no es un constructor, por


consiguiente la clase se compilará y al ejecutarse el método Crowle no se ejecutará –
pues no ha sido llamado-.

Respuesta 4)

2)Error en tiempo de compilación.

Ocurre un error cuando la clase Severn intenta llamar al constructor con cero parámetros
en la clase Base.

Respuesta 5)

3)El constructor predefinido no toma parámetros.


4)El constructor predefinido no se crea si la clase contiene algún constructor propio

41
Tutorial para el examen de certificación: SCJP 1.2

Otras Fuentes de este tema:


Esta tema es cubierto en el Tutorial de Sun :
http://java.sun.com/docs/books/tutorial/java/javaOO/constructors.html
Richard Baldwin cubre este tema en
http://www.Geocities.com/Athens/Acropolis/3797/Java042.htm#default constructor
Jyothi Krishnan en:
http://www.geocities.com/SiliconValley/Network/3693/obj_sec1.html#obj3
Bruce Eckel Thinking In Java
Capítulo 4

42
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 4
Establecer los tipos de datos validos de retorno para cualquier método, dada las
declaraciones de todos lo métodos relacionados con este o con la clase padre.

Nota de este objetivo


La frase del objetivo parece ser bastante obscura. Parece estar pidiéndote que entiendas
la diferencia entre sobrecarga y sobrescritura.

Para aprovechar mejor este objetivo necesitas una comprensión básica sobre la
sobrecarga y sobrescritura de métodos. Esto se ve en la:

Sección 6: Orientación a Objetos, sobrecarga y sobreescritura en tiempo de ejecución

Métodos en la misma clase


Si dos o más métodos en la misma clase tienen el mismo nombre, se dice que el método
esta sobrecargado. Puedes tener dos métodos en una clase con el mismo nombre pero
deben tener parámetros de diferente tipo y en diferente orden.

Es el orden de los parámetros y los tipos de los mismos los que distinguen entre
cualquiera de dos versiones de un método sobrecargado a uno en especial. El tipo de dato
de retorno no contribuye a la distinción entre métodos.

El código siguiente generará un error en tiempo de compilación, el compilador observa


en amethod un intento por definir el mismo método dos veces. Causa un error que dirá
algo como lo siguiente:

method redefined with different return type: void amethod(int)


was int amethod(int)

class Same{
public static void main(String argv[]){
Over o = new Over();
int iBase=0;
o.amethod(iBase);
}
//Las siguientes definiciones generan un error al
compilar
public void amethod(int iOver){
System.out.println("Over.amethod");
}
public int amethod(int iOver){
System.out.println("Over int return method");
return 0;
}

43
Tutorial para el examen de certificación: SCJP 1.2

El tipo de dato de retorno no contribuye a realizar la distinción


entre un método y otro.

Métodos en una subclase.

Puedes sobrecargar un método en una subclase. Todo lo que se requiere es que la nueva
versión debe tener parámetros de diferente tipo y en diferente orden. Los nombres de los
parámetros o el tipo de dato retornado por el método no se toman en cuenta para la
sobrecarga de métodos.

Si vas a sobrescribir un método, por ejemplo para reemplazar su funcionalidad


completamente en una subclase, la versión sobrescrita del método debe tener la misma
definición que la versión de la clase base de la que esta descendiendo. Esto incluye el tipo
de dato de retorno. Si creas un método en una subclase con el mismo nombre y
definición pero retorna un tipo de dato distinto, generarás el mismo mensaje de error que
en el ejemplo anterior. Es decir:

method redefined with different return type: void amethod(int)


was int amethod(int)

El compilador lo ve como un intento fallido por sobrecargar el método en lugar de verlo


como una sobrescritura del método.

Preguntas

Pregunta 1)

Dada la siguiente definición de clase:

public class Upton{


public static void main(String argv[]){

44
javaHispano. Tu comunidad, tu lenguaje.

}
public void amethod(int i){}
//Here
}

¿Cuáles de las líneas siguientes son válidas para ser colocadas después del comentario
//Here?

1) public int amethod(int z){}


2) public int amethod(int i,int j){return 99;}
3) protected void amethod(long l){ }
4) private void anothermethod(){}

Pregunta 2)

Dada la siguiente definición de clase:

class Base{
public void amethod(){
System.out.println("Base");
}
}
public class Hay extends Base{
public static void main(String argv[]){
Hay h = new Hay();
h.amethod();
}

¿Cuál de los siguientes método puede ser de la clase Hay para que compile y provoque
que el programa muestre la cadena “Hay” ?

1) public int amethod(){ System.out.println("Hay");}


2) public void amethod(long l){ System.out.println("Hay");}
3) public void amethod(){ System.out.println("Hay");}
4) public void amethod(void){ System.out.println("Hay");}

Respuestas

Respuesta 1)

45
Tutorial para el examen de certificación: SCJP 1.2

2) public int amethod(int i, int j) {return 99;}


3) protected void amethod (long l){}
4) private void anothermethod(){}

La opción 1 no compilara por dos razones. La primera es que obviamente exige que un
entero sea retornado- y como podemos ver hace falta un return -. La otra es que es
evidente un intento por redefinir un método dentro de la misma clase. El cambio de
nombre del parámetro de i a z no tiene efecto y un método no puede ser sobrescrito
dentro de la misma clase.

Respuesta 2)

3) public void amethod(){ System.out.println("Hay");}

La opción 3 es una sobrescritura del método de la clase Base, para alguna invocación de
esta versión se utilizarán cero parámetros

La opción 1 generará un error que indicará que se está intentando redefinir un método
con un diferente tipo de dato de retorno. Aunque la opción 2 compilará, la llamada a
amethod invocará el método de la clase Base y la salida sea la cadena “Base”. La
opción 4 fue diseñada para sorprender a aquellos con una cabeza llena de C/C++, en Java
no hay tal cosa: la utilización de void para indicar que no hay parámetros.

Otras Fuentes de este tema:

Jyothi Krishnan
http://www.geocities.com/SiliconValley/Network/3693/obj_sec1.html#obj4

En esta liga Jyothi sugiere que vayas al objetivo 19:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec6.html#obj19

46
javaHispano. Tu comunidad, tu lenguaje.

Sección 2. Control de Flujo y Manejo de Excepciones.


Objetivo 1.
Escribir código que use sentencias if y switch e identificar los tipos validos de
argumentos para estas sentencias.

La sentencia if/else.

Ls sentencia if/else funciona en Java tal como podrías esperar que funcione en otros
lenguajes. las sentencias switch/case tienen unas peculiaridades.

La sintaxis para la sentencia if/else es:

if(condicion tipo_boolean){
//si el boolean es verdadero se hace esto
}else {
//sino, se hace esto
}

Java no tiene la palabra clave "then" como en Visual Basic.

Las llaves son un indicador general en Java de una declaración compuesta que permite
ejecutar múltiples líneas de código como resultado de alguna evaluación. Esto se conoce
como bloque de código. La parte del "else" siempre es opcional.

Una idiosincrasia de Java es que la sentencia if debe tomar un valor del tipo boolean.
No puedes usar la convención de C/C++ donde cualquier valor distinto de cero es
verdadero y 0 es falso.

Así , en Java lo siguiente simplemente no compilará:

int k =-1;
if(k){//no se compilará!
System.out.println("do something");
}

Esto debido a que debes efectuar explícitamente una pregunta sobre la variable k que
devuelva un valor tipo boolean, como en el ejemplo siguiente:

if(k == -1){
System.out.println("do something"); //compilación OK!
}

Así como en C/C++ puedes no utilizar las llaves:

47
Tutorial para el examen de certificación: SCJP 1.2

boolean k=true;
if(k)
System.out.println("do something");

Esto a veces es considerado un mal estilo de programación, porque si modificas el código


después para incluir declaraciones adicionales estas quedarán fuera del bloque
condicional (qué solo abarca una línea por no utilizar llaves) Así:

if(k)
System.out.println("do something");
System.out.println("also do this");

La segunda línea siempre se ejecutará.

La Sentencia switch

La opinión de Peter van der Lindens sobre la sentencia switch se resume cuando dice:

"Muerte a la sentencia switch"

Este es un asunto al que le debes prestar atención extra. El argumento de una sentencia
switch debe ser un byte, char, short o un int. Puedes encontrar un ejercicio en
el examen que use un float o un long como argumento en una sentencia switch. Una
pregunta bastante común parece estar sobre el uso de la sentencia break en el proceso
descendente a través de una sentencia switch. Aquí hay un ejemplo de este tipo de
pregunta.

int k=10;
switch(k){
case 10:
System.out.println("ten");
case 20:
System.out.println("twenty");
}

El sentido común nos indicaría que después de ejecutar las instrucciones que siguen la
primera sentencia case, y habiéndose encontrado con otra sentencia case, el compilador
terminaría su descenso a través de la sentencia switch. Sin embargo, por razones mejor
conocidas solo por los diseñadores del lenguaje, una sentencia case solo se detiene
cuando se encuentran con una sentencia break. Como resultado, en el ejemplo anterior
las cadenas: "ten" y "twenty" son mostradas.

Otra pequeña peculiaridad que puede surgir en las preguntas es donde colocar la
sentencia default.

48
javaHispano. Tu comunidad, tu lenguaje.

La cláusula default no necesita ir al final de una sentencia case.

El lugar convencional para la sentencia default está al final de las opciones case. Así
normalmente el código se escribirá como sigue:

int k=10;
switch(k){
case 10:
System.out.println("ten");
break;
case 20:
System.out.println("twenty");
break;
default:
System.out.println("This is the default output");
}

Esta aproximación refleja la manera en que piensa la mayoría de las personas. Una vez
que se han probado todas las posibilidades, se realiza la sentencia default. Sin
embargo, el código de una sentencia switch con la sentencia default hasta arriba es
sintácticamente correcto, pero no aconsejable.

int k=10;
switch(k){
default: //Coloca default hasta abajo y no acá
System.out.println("This is the default output");
break;
case 10:
System.out.println("ten");
break;
case 20:
System.out.println("twenty");
break;
}

Argumentos validos para las sentencias if y switch.


Como mencioné anteriormente una sentencia if puede tomar solo un valor tipo boolean
y una sentencia switch puede tomar solamente un byte, char, short o un int.

El operador ternario ?

49
Tutorial para el examen de certificación: SCJP 1.2

Algunos programadores dicen que el operador ternario es útil. Yo no considero para que.
No se menciona específicamente en los objetivos así que por favor háganme saber si
aparece en su examen.

Pregunta 1)
¿Qué pasará cuando intentes compilar y ejecutar el siguiente código?

public class MyIf{


boolean b;
public static void main(String argv[]){
MyIf mi = new MyIf();
}
MyIf(){
if(b){
System.out.println("The value of b was true");
}
else{
System.out.println("The value of b was false");
}
}
}

1) Error en tiempo de compilación: la variable b no fue inicializada


2) Error en tiempo de compilación: el parámetro para la sentencia if debe evaluar a un
boolean
3) Error en tiempo de compilación: no se puede crear y asignar un valor simultáneamente
a un boolean
4) Compilación y ejecución mostrando el segundo mensaje.

Pregunta 2)
¿Qué pasará cuando intentes compilar y ejecutar este código?

public class MyIf{


public static void main(String argv[]){
MyIf mi = new MyIf();
}
MyIf(){
boolean b = false;

50
javaHispano. Tu comunidad, tu lenguaje.

if(b=false){
System.out.println("The value of b is"+b);
}
}
}

1) Error en tiempo de ejecución: un boolean no puede agregarse con el operador +


2) Error en tiempo de compilación: el parámetro para la sentencia if debe evaluar a un
boolean
3) Error en tiempo de compilación: no se puede crear y asignar un valor simultáneamente
a un boolean
4) Compilación y ejecución sin salida.

Pregunta 3)
¿Qué pasará cuando intentes compilar y ejecutar este código?

public class MySwitch{

public static void main(String argv[]){


MySwitch ms= new MySwitch();
ms.amethod();
}

public void amethod(){

char k=10;
switch(k){
default:
System.out.println("This is the default output");
break;
case 10:
System.out.println("ten");
break;
case 20:
System.out.println("twenty");
break;
}
}
}

1) Ninguna de estas opciones


2) Error en tiempo de compilación: el valor para el switch debe ser de tipo entero
3) Se Compilará y ejecutará mostrando "This is the default output"
4) Se Compilará y ejecutará mostrando "ten"

51
Tutorial para el examen de certificación: SCJP 1.2

Pregunta 4)
¿Qué pasará cuando intentes compilar y ejecutar el siguiente código?

public class MySwitch{

public static void main(String argv[]){


MySwitch ms= new MySwitch();
ms.amethod();
}

public void amethod(){

int k=10;
switch(k){
default: //Put the default at the bottom, not here
System.out.println("This is the default output");
break;
case 10:
System.out.println("ten");
case 20:
System.out.println("twenty");
break;
}
}
}

1) Ninguna de estas opciones


2) Error en tiempo de compilación: el valor para el switch debe ser de tipo entero
3) Se Compilará y ejecutará mostrando "This is the default output"
4) Se Compilará y ejecutará mostrando "ten"

Pregunta 5)
¿ De las siguientes líneas, cual podría usarse como parámetro para una declaración
switch?

1) byte b=1;
2) int i=1;
3) boolean b=false;
4) char c='c';

Respuestas

Respuesta 1)

4) Compilación y ejecución mostrando el segundo mensaje.

52
javaHispano. Tu comunidad, tu lenguaje.

Debido a que la variable boolean b se creó al nivel de clase, no necesita ser inicializada
explícitamente y en cambio toma el valor predefinido de un boolean que es falso. Una
sentencia if debe evaluar un valor boolean y así la variable b cumple este criterio.

Respuesta 2)

4) Compilación y ejecución sin salida.

Debido a que la variable b es un boolean no habrá ningún error causado por la sentencia
if. Si b fuera de cualquier otro tipo de dato hubiera ocurrido un error cuando intentaras
realizar una asignación en lugar de una comparación. La expresión:

if(b=false)

es una asignación y normalmente representa un error del programador. A menudo el


programador tenía en mente decir:

if (b==false)

Si el tipo de dato de b hubiera sido cualquiera menos boolean habría ocurrido un error
al compilarse. El requisito para la sentencia if es que devuelva un boolean y debido a
que:

if (b=false)

devuelve un boolean (false), esto es aceptable (pero inservible).

Respuesta 3)

4) Se Compilará y ejecutará mostrando "ten"

Respuesta 4)

1) Ninguna de estas opciones

Debido a la falta de una sentencia break después de la línea:

System.out.println("ten");

la salida real será:


"ten" seguido de "twenty"

Respuesta 5)

53
Tutorial para el examen de certificación: SCJP 1.2

1) byte b=1;
2) int i=1;
4) char c='c';

Una sentencia switch puede tomar únicamente a un byte, char short o a un int
como parámetro.

Otras Fuentes para este tema:


El tutorial de Sun
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/while.html

Richard Baldwin Cubre este tema en:


http://www.Geocities.com/Athens/Acropolis/3797/Java026.htm#the if-else statement

Jyothi Krishnan en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec2.html#obj5

54
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 2.
Escribir código que use todas las formas de ciclos incluyendo el etiquetado y
desetiquetado, el uso de break y continue y conocer los valores tomados por las
variables contadoras de los ciclos durante y después de la ejecución de cada ciclo.

La sentencia for
El método más común para enciclar es usar la sentencia for. Como en C++ y a
diferencia de C, la variable que controla el ciclo puede crearse e inicializarse dentro de la
sentencia for. Así

public class MyLoop{


public static void main(String argv[]){
MyLoop ml = new MyLoop();
ml.amethod();
}

public void amethod(){


for(int K=0;K<5;K++){
System.out.println("Outer "+K);
for(int L=0;L<5;L++)
{System.out.println("Inner "+L);}
}
}
}

Este código iterara 5 veces en el ciclo interno por cada iteración del ciclo externo. Así la
salida será:

Outer 0
Inner 0
Inner 1
Inner 2
Inner 3
inner 4
Outer 1
Inner 0
Inner 2

Etc, etc.

El sentencia for es el equivalente del ciclo for/next en Visual Basic. Debes tomar en
cuanta que la sintaxis es:

for(inicialización; expresión condicional; incremento)

55
Tutorial para el examen de certificación: SCJP 1.2

La expresión condicional debe ser una expresión tipo boolean de una manera similar a
la sentencia if. En el código ejemplo sobre la sentencia for, esta fue seguida por un
bloque del código señalado por llaves. De la misma manera que un sentencia if no exige
un bloque de código, puedes tener una sentencia for que simplemente maneje una línea,
de esta manera:

for(int i=0;i<5;i++)
System.out.println(i);

Nota que en ninguna de las versiones se termina la línea del for con punto y coma. Si lo
haces, el ciclo for solo iterara en esa línea hasta que la condición se cumpla y entonces
el programa continuará en "línea recta". No tienes que crear variable de
inicialización(como en este caso) dentro del ciclo for, pero si lo haces significará que la
variable saldrá del alcance en cuanto se termine el ciclo. Esto puede ser considerado una
ventaja por lo que se refiere a mantener el alcance de las variables tan pequeño como sea
posible.

Los ciclos while y do, nada inesperado.

Los ciclos while y do funcionan mucho más de lo que esperarías de su equivalente en


otros lenguajes.

Así un while se ejecutará cero o más veces según la condición y el do se ejecutará una o
más veces. La sintaxis ara el ciclo while es:

while(condición){
cuerpodelciclo;
}

La condición es una expresión tipo boolean parecida al de una sentencia if. De nuevo
no puedes usar la convención de C/C++ donde 0 es verdadero y cualquier otro valor es
falso.

De manera que podrías crear un ciclo while de la siguiente manera:

while(i<4){
i++;
System.out.println("Loop value is :"i);
}

Nota que si la variable i valiera 4 o más cuando se alcanzara la sentencia while no se


produciría ningún resultado. Por contraste un ciclo do siempre se ejecutará, al menos, una
vez.

56
javaHispano. Tu comunidad, tu lenguaje.

Así con el código siguiente siempre conseguirás por lo menos una ejecución del cuerpo
del ciclo no importando el valor de la variable i al entrar en el ciclo.

do{
System.out.println("value of : "+i);
} while (i <4);

Muchos programadores intentan usar el ciclo for en lugar del ciclo while cuando
pueden concentrar en una sola línea la creación, inicialización, prueba e incremento del
contador.

La sentencia goto, ¿ciencia o religión?

Los diseñadores de Java decidieron que ellos estaban de acuerdo con el gurú de la
programación Edsger Dijkstra quien escribió un artículo famoso titulado "Goto
considered harmful". Debido a que el uso indistinto de sentencias goto pueden dar como
resultado un código, cual espagueti, difícil de mantener, su uso se ha reducido y es
considerado como un mal estilo de programación. Hay situaciones donde sería útil y para
ayudar en esas situaciones Java ofrece las versiones etiquetadas y desetiquetadas de las
palabras clave break y continue.

Break y Continue

Estas sentencias te permiten interrumpir condicionalmente ciclos. Sin embargo, no te


permiten saltar a otra parte de programa. Es probable que el examen incluya este tema en
la forma de un conjunto de ciclos anidados. Tienes que indicar que números se mostrarán,
al ejecutar el código, antes de que termine el ciclo debido al mecanismo de la sentencia
break.

Este es un ejemplo de la clase de preguntas irritables que probablemente te encuentres en


el examen.

public class Br{


public static void main(String argv[]){
Br b = new Br();
b.amethod();

public void amethod(){

for(int i=0;i <3;i ++){


System.out.println("i"+i+"\n");
outer://<==Point of this example
if(i>2){
break outer;//<==Point of this example

57
Tutorial para el examen de certificación: SCJP 1.2

}//End of if
for(int j=0; j <4 && i<3; j++){
System.out.println("j"+j);
}//End of for

}//End of for
}//end of Br method

Tienes que elegir que combinación de letras se mostrará con la ejecución del código. A
propósito el código “\n” (en caso de que aún no lo sepas) significa que se mostrará una
línea en blanco.

Saltar a una Etiqueta.

Es deseable a menudo, saltar de un ciclo interno a un ciclo externo dada una condición.
Puedes hacer esto etiquetando las sentencias break y continue.

Una etiqueta es simplemente una palabra no reservada seguida de dos puntos. Poniendo
el nombre de la etiqueta después del break o continue tu código saltará hasta la
etiqueta. Esto es conveniente para hacer condicional una parte de un ciclo. Por supuesto,
puedes hacer lo mismo con una sentencia if, pero una sentencia break es más
conveniente. No puedes saltar a otro ciclo o a otro método pero una vez terminado el
ciclo actual es muchas veces muy útil.

La sentencia break abandona completamente el proceso del ciclo activo, la


sentencia continue abandona únicamente el proceso de la iteración activa del
ciclo activo

Tomando en cuenta el siguiente código:

public class LabLoop{


public static void main(String argv[]){
LabLoop ml = new LabLoop();
ml.amethod();
}

public void amethod(){


outer:
for(int i=0;i<2;i++){
for(int j=0;j<3;j++){
if(j>1)
//prueba con break en lugar de continue
continue outer;
System.out.println("i "+ i + " j "+j);

58
javaHispano. Tu comunidad, tu lenguaje.

}//fin del for externo outer


System.out.println("Continuing");
}//fin de amethod
}
Se mostrará lo siguiente:
i 0 j 0
i 0 j 1
i 1 j 0
i 1 j 1
Continuing

Si sustituyeras la sentencia continue por break, el contador i se detendría en cero ya


que el proceso del ciclo externo se abandonaría en lugar de simplemente continuar al
siguiente incremento.

Pregunta 1)
¿Que pasará cuando intentes compilar y ejecutar el siguiente código en un método?

for(int i=0;i<5;){
System.out.println(i);
i++;
continue;
}

1) Error en tiempo de compilación, sentencia for incorrecta.


2) Error en tiempo de compilación: continue dentro de un for
3) Error en tiempo de ejecución: sentencia continue no alcanzada.
4) Se compilará y se ejecutará mostrando los valores del 0 al 4.

Pregunta 2)
¿Qué pasará cuando intentes compilar y ejecutar el siguiente código?

public class LabLoop{


public static void main(String argv[]){

59
Tutorial para el examen de certificación: SCJP 1.2

LabLoop ml = new LabLoop();


ml.amethod();
mainmethod:
System.out.println("Continuing");
}

public void amethod(){


outer:
for(int i=0;i<2;i++){
for(int j=0;j<3;j++){
if(j>1)
break mainmethod;
System.out.println("i "+ i + " j "+j);
}
}//End of outer for
}
}

1)
i 0 j 0
i 0 j 1
Continuando

2)
i 0 j 0
i 0 j 1
i 1 j 0
i 1 j 1
Continuando

3)
Error en tiempo de Compilación.

4)
i 0 j 0
i 0 j 1
i 1 j 0
i 1 j 1
i 2 j 1
Continuando

Pregunta 3)
¿Qué pasará cuando intentes compilar y ejecutar el siguiente código?

public void amethod(){


outer:
for(int i=0;i<2;i++){

60
javaHispano. Tu comunidad, tu lenguaje.

for(int j=0;j<2;j++){
System.out.println("i="+i + " j= "+j);
if(i >0)
break outer;
}
}
System.out.println("Continuing with i set to ="+i);
}

1)Error en tiempo de compilación.

2)
i=0 j= 0
i=0 j= 1
i=1 j= 0

3)
i=0 j= 0
i=0 j= 1
i=1 j= 0
i=2 j= 0

4)
i=0 j= 0
i=0 j= 1

Pregunta 4)
¿Qué pasará cuando intentes compilar y ejecutar el siguiente código?

int i=0;
while(i>0){
System.out.println("Value of i: "+i);

}
do{
System.out.println(i);
} while (i <2);

1)
Value of i: 0
Seguido de
0
1
2

2)
0
1
2

61
Tutorial para el examen de certificación: SCJP 1.2

3)
Value of i: 0
Seguido de una secuencia de 0’s

4) Mostrará una secuencia de 0’s

Respuestas

Respuesta 1)

4)Se compilará y se ejecutará mostrando los valores del 0 al 4.

Esta es una versión un tanto extraña de la sentencia for, pero es totalmente valida.

Respuesta 2)
3)
Error en tiempo de Compilación.

No puede saltar arbitrariamente a otro método, esto traerían consigo todo los males ya
manifestados sobre la sentencia goto.

Respuesta 3)

1)Error en tiempo de compilación.

Realmente esta no es una pregunta acerca del funcionamiento de break y continue.


Este código no se compilará porque la variable utilizada no existe fuera el ciclo for. Por
lo tanto, la sentencia System.out.println, causará un error en tiempo de
compilación.

Respuesta 4)

4)Mostrará una secuencia de 0’s

El ciclo while no ejecutará nada en absoluto si la condición no es verdadera en su


primera iteración y debido a que no hay ningún incremento de algún valor en el ciclo do
se ejecutará infinitamente.

Otras Fuentes para este tema


El tutorial de Sun
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/while.html

Jyothi Krishnan
http://www.geocities.com/SiliconValley/Network/3693/obj sec2.html#obj6

62
javaHispano. Tu comunidad, tu lenguaje.

Richard Baldwin
http://www.Geocities.com/Athens/Acropolis/3797/Java026.htm#flow of control

Bruce Eckel
http://codeguru.earthweb.com/java/tij/tij0045.shtml#Heading131

63
Tutorial para el examen de certificación: SCJP 1.2

Objetivo 3.

Escribir código que haga un uso apropiado de las excepciones y las cláusulas del manejo
de excepciones (try, catch y finally), declarar métodos y sobreescribir métodos que
lanzen excepciones.

Las sentencias try y catch son parte del manejo de excepciones construido en Java. Ni
C/C++ " ni Visual Basic tienen un equivalente directo a las excepciones construidas en
Java. C++ soporta excepciones pero es de manera opcional, y Visual Basic soporta la
captura de errores con On Error/Goto.

Las excepciones en Java son construidas como parte del lenguaje. Por ejemplo si estas
realizando instrucciones de Entrada y Salida (I/O) debes manipular excepciones. Puedes
colocar por supuesto un manejador nulo que no haga nada. Lo siguiente es una pequeña
parte del código que he acostumbrado a usar con Borland/Inprise JBuilder para detener
temporalmente la salida de la consola y esperar que cualquier tecla sea presionada

import java.io.*;
public class Try{

public static void main(String argv[]){


Try t = new Try();
t.go();
}//End of main
public void go(){
try{
InputStreamReader isr = new InputStreamReader(System.in);
BufferedReader br = new BufferedReader(isr);
br.readLine();
} catch(Exception e){
/*No se hace nada cuando ocurre la excepción*/
} //End of try
System.out.println("Continuing");
}//End of go
}

En este caso no se hace nada cuando ocurre un error, pero el programador aun reconoce
que puede ocurrir un error. Si quitas las cláusulas try y catch el código simplemente no
compilará. El compilador sabe que los métodos de I/O pueden causar excepciones y exige
código para manejar esas posibles excepciones.

Comparando con Visual Basic y C/C++

Esto es un poco más riguroso que en Visual Basic o en C/C++ que te permite lanzar
"sucia y rápidamente" programas que fingen que están en un mundo donde los errores no

64
javaHispano. Tu comunidad, tu lenguaje.

ocurren. No es exactamente una programación esclavizada y disciplinada, las


excepciones sólo te animan persuasivamente a "hacer las cosas correctamente".

La Cláusula finally

Una de las rarezas que probablemente te preguntarán en el examen, es bajo qué


circunstancias se ejecuta la cláusula finally de un bloque try/catch. La respuesta
mas corta a esto es que la cláusula finally casi siempre se ejecuta, incluso cuando podrías
pensar que no se ejecutaría. Hemos dicho que, la trayectoria de ejecución de las
sentencias try/catch/finally es algo con lo que realmente necesitas jugar para
convencerte de lo qué es lo que pasa bajo qué circunstancias.

la cláusula finally de un bloque try/catch siempre se ejecutará, aun


cuando haya cualquier sentencia de retorno en la parte try/catch

Uno de las pocas ocasiones donde la cláusula finally no se ejecutará es si hay una
llamada a:

System.exit(0);

El examen tiende a no intentar sorprenderte con esta excepción a la regla.

El examen es más propenso a dar ejemplos que incluyan declaraciones de retorno para
engañarte y hacerte pensar que el código retornará sin ejecutar la sentencia finally. No
te despistes, la cláusula finally casi siempre se ejecutará.

La cláusula try/catch debe capturar los errores en el orden natural de su jerarquía. Así,
no puedes intentar capturar la excepción Exception, que es mas general, antes de
intentar capturar la excepción IOException que es más específica.(NT: en otras
palabras, debes de intentar capturar primero las más especificas y luego las más
generales)

El siguiente código no se compilará:

try{
DataInputStream dis = new DataInputStream(System.in);
dis.read();
}catch (Exception ioe) {
}catch (IOException e) { //error en tiempo de compilación
}finally{}

65
Tutorial para el examen de certificación: SCJP 1.2

Este código generará un mensaje de error en tiempo de compilación: IOException


nunca se alcanzará.

Sobrescribiendo métodos que lanzan excepciones

Un método sobrescrito en una subclase solo puede lanzar excepciones declaradas en la


clase padre o excepciones que sean hijas de las excepciones declarados en la clase padre.
Esto es sólo valido para métodos sobrescritos y no para métodos sobrecargados. Así, si
un método tiene exactamente el mismo nombre y argumentos puede lanzar únicamente
excepciones declaradas en la clase padre, o excepciones que son hijos de excepciones de
la declaración de la clase padre. No obstante puede lanzar ninguna o pocas excepciones.
Así el ejemplo siguiente no se compilará:

import java.io.*;

class Base{
public static void amethod()throws FileNotFoundException{}
}

public class ExcepDemo extends Base{


//No se compilara, la excepción que se intenta lanzar no esta
//en la versión del método amethod en la clase Padre(Base)
public static void amethod()throws IOException{}
}

Si fuera el método de la clase padre el que estuviera lanzando a IOException y el método


en la clase hijo el que estuviera lanzando a FileNotFoundException el código si
compilaría(NT: debido a que FileNotFoundException es subclase de IOException). De
nuevo, recuerda que esto sólo se aplica a los métodos sobrescritos, no hay ninguna regla
similar para los métodos sobrecargados. Un método sobrescrito en una subclase también
puede lanzar excepciones.

Pregunta 1)

66
javaHispano. Tu comunidad, tu lenguaje.

¿Qué pasara cuando intentes compilar y ejecutar el siguiente código?

import java.io.*;

class Base{
public static void amethod()throws FileNotFoundException{}
}

public class ExcepDemo extends Base{


public static void main(String argv[]){
ExcepDemo e = new ExcepDemo();
}
public static void amethod(){}

protected ExcepDemo(){
try{
DataInputStream din = new DataInputStream(System.in);
System.out.println("Pausing");
din.readChar();
System.out.println("Continuing");
this.amethod();
}catch(IOException ioe) {}
}

1)Error en tiempo de compilación causado por el constructor protegido.


2)Error en tiempo de compilación causado por que amethod ha declarado excepciones.
3)Error al ejecutar: amethod no ha declarado excepciones.
4)Se compilara y se ejecutara mostrando: “Pausing” y “Continuing” después de que
una tecla es pulsada.

Pregunta 2)

¿Qué pasara cuando intentes compilar y ejecutar el siguiente código?

import java.io.*;

class Base{
public static void amethod()throws FileNotFoundException{}
}

public class ExcepDemo extends Base{


public static void main(String argv[]){
ExcepDemo e = new ExcepDemo();
}

public static void amethod(int i)throws IOException{}

67
Tutorial para el examen de certificación: SCJP 1.2

private ExcepDemo(){
try{
DataInputStream din = new DataInputStream(System.in);
System.out.println("Pausing");
din.readChar();
System.out.println("Continuing");
this.amethod();
}catch(IOException ioe) {}
}

1)Error en tiempo de compilación causado por el constructor privado.


2)Error en tiempo de compilación: amethod ha declarado excepciones que no están en la
versión de la clase base.
3)Error al ejecutar: amethod ha declarado excepciones que no están en la versión de la
clase base.
4)Se compilara y se ejecutara mostrando: “Pausing” y “Continuing” después de que
una tecla es pulsada.

Pregunta 3)

¿Qué pasara cuando intentes compilar y ejecutar el siguiente código?


import java.io.*;

class Base{
public static void amethod()throws FileNotFoundException{}
}

public class ExcepDemo extends Base{


public static void main(String argv[]){
ExcepDemo e = new ExcepDemo();
}
public static void amethod(int i)throws IOException{}

private boolean ExcepDemo(){


try{
DataInputStream din = new DataInputStream(System.in);
System.out.println("Pausing");
din.readChar();
System.out.println("Continuing");
this.amethod();
return true;
}catch(IOException ioe) {
}finally{
System.out.println("finally");
}

68
javaHispano. Tu comunidad, tu lenguaje.

return false;
}

1)Se compilara y se ejecutara sin mostrar algo.


2)Mostrando: “Pausing”, “Continuing” y “Finally”
3)Error al ejecutar: amethod ha declarado excepciones que no están en la versión de la
clase
base.
4)Se compilara y se ejecutara mostrando: “Pausing” y “Continuing” después de que
una tecla es pulsada.

Pregunta 4)

¿Qué pasara cuando intentes compilar y ejecutar el siguiente código?

import java.io.*;

class Base{
public static void amethod()throws FileNotFoundException{}
}

public class ExcepDemo extends Base{


public static void main(String argv[]){
ExcepDemo e = new ExcepDemo();
}

public boolean amethod(int i){


try{
DataInputStream din = new DataInputStream(System.in);
System.out.println("Pausing");
din.readChar();
System.out.println("Continuing");
this.amethod();
return true;
}catch(IOException ioe) {
}finally{
System.out.println("Doing finally");
}
return false;
}

ExcepDemo(){
amethod(99);
}
}

69
Tutorial para el examen de certificación: SCJP 1.2

1)Error en tiempo de compilación: amethod no lanza FileNotFounfException


2)Se compila, se ejecuta y muestra “Pausing” y “Continuing”
3) Se compila, se ejecuta y muestra “Pausing” ,“Continuing” y “Doing finally”
4)Error en tiempo de compilación, la cláusula finally nunca se alcanza.

Respuestas

Respuesta 1)

4)Se compilara y se ejecutara mostrando: “Pausing” y “Continuing” después de que


una tecla es pulsada.

Un método sobrescrito en una subclase no debe lanzar Excepciones no lanzadas en la


clase base. En el caso del método amethod este no lanza ninguna excepción y en
consecuencia compilará, así sin alguna indicación. No hay razón alguna por la que un
constructor no pueda protegerse.

Respuesta 2)

4)Se compilara y se ejecutara mostrando: “Pausing” y “Continuing” después de que


una tecla es pulsada.

En este versión amethod se ha sobrecargado de manera que no hay ninguna restricción


sobre qué excepciones pueden o no ser lanzadas.

Respuesta 3)

1)Se compilara y se ejecutara sin mostrar algo.

OK, aquí me he salido un poco fuera del tema. Observa que lo que antes era un
constructor ahora tiene un valor del retorno. Esto lo convierte en un método ordinario y
por lo tanto no se llama cuando se crea una instancia de la clase.

Respuesta 4)

3) Se compila, se ejecuta y muestra “Pausing” ,“Continuing” y “Doing finally”

La cláusula finally siempre se ejecuta

Otras Fuentes para este tema


Este tema es cubierto en el Tutorial de SUN
http://java.sun.com/docs/books/tutorial/essential/exceptions/definition.html

Richard Baldwin cubre este tema en:


http://www.geocities.com/Athens/Acropolis/3797/Java030.htm

70
javaHispano. Tu comunidad, tu lenguaje.

y
http://www.geocities.com/Athens/Acropolis/3797/Java056.htm

Jyothi Krishnan en
http://www.geocities.com/SiliconValley/Network/3693/obj_sec2.html#obj7

Bruce Eckel Thinking in Java


Capítulo 9)

71
Tutorial para el examen de certificación: SCJP 1.2

Sección 3. Recolector de basura –Garbage Collector-


Objetivo 1.
Exponer el comportamiento que se garantiza por el sistema de recolección de basura y
escribir código que explícitamente haga objetos elegibles para la recolección.

¿Por qué querrías utilizar el recolector de basura?

Puedes ser un programador de Java muy experimentado y nunca haber tenido que
familiarizarte con los detalles del recolector de basura. Incluso la expresión
recolección de basura es un poco rara. En este contexto significa la liberación de
memoria que se ha asignado y que ya ha sido usada por el programa. Cuando ya no se
necesita una parte de la memoria asignada ésta puede considerarse como basura, es decir
algo que ya no se necesita; y que simplemente está desordenando espacio útil.

Una de las grandes cualidades aclamadas de Java es que no tienes que preocuparte por la
recolección de basura. Si vienes de programar con Visual Basic puede parecerte absurdo
que algún sistema, por si mismo, no cuide este detalle. En C/C++ el programador tiene
que seguir, de forma manual, el rastro la asignación y desasignación de la memoria.
Como resultado de esto, las "fugas de memoria" son una gran fuente de errores difíciles
de rastrear. Ésta es una de las razones por las que algunas versiones de aplicaciones de
Microsoft como Word o Excel, se detienen apenas comienzan a ejecutarse. Las fugas de
memoria a la larga, finalmente hacen que el sistema entero se cuelgue y que te veas en la
necesidad de pulsar ese gran interruptor luminoso. En alguna parte, en esos centenares de
miles de líneas de código en C++, un programador asignó un bloque de memoria pero se
le olvido asegurarse de liberarla.

Java y el recolector de basura.

A diferencia de C/C++, Java libera automáticamente las referencias que no se están


utilizando. No tienes que pasar por el trauma de buscar asignaciones de memoria que
nunca son liberadas y por consiguiente, no necesita saber cómo asignar ó cómo saber el
tamaño de un tipo de datos para asegurar la compatibilidad de la plataforma. Así qué ¿Por
qué querrías conocer mas los detalles del recolector de basura? Dos respuestas saltan a mi
mente, una es aprobar el examen y la otra es comprender lo que ocurre en circunstancias
extremas.

Por ejemplo, si escribes código que genere números muy grandes de objetos o de
variables te puede ser útil saber cuando se liberan las referencias.
Si lees algún newsgroups verás a personas informando en ocasiones de ciertas
aplicaciones Java que agotan los recursos y hacen que todo se caiga. Esto no estaba en el
folleto del SUN cuando lanzaron Java.

72
javaHispano. Tu comunidad, tu lenguaje.

Siguiendo la filosofía de la recolección de basura automática, puedes sugerir o


animar que la JVM realice la recolección de basura, pero no la puedes forzar.

Permíteme remarcar el punto, no puedes forzar la ejecución de la


recolección de basura, sólo puedes sugerirla.

A primera vista el termino finalización me suena un poco como a los destructores en C++
usados para limpiar los recursos antes de que se destruya un objeto. La diferencia es qué
en Java los recursos internos no necesitan ser liberados durante la finalización porque el
recolector de basura cuida la asignación de memoria. Sin embargo si tienes
recursos externos como un archivo de información, puedes usar la finalización para
liberarlos.

Escribir ejercicios o practicar con el recolector de basura es un poco complejo ya


que no hay manera de conseguir código que indique cuando está disponible para la
recolección de basura. No puedes escribir un fragmento de código con una sintaxis como
la siguiente:

if(EligibleForGC(Object){ //código no real


System.out("Ready for Garbage");
}

Debido a esto solo tienes que aprender las reglas.

Una vez que una variable no es referenciada en mucho tiempo está disponible para ser
recolectada por el recolector de basura.

Puedes sugerir la ejecución del recolector de basura con el método


System.gc(), pero esto no garantiza que se ejecutará inmediatamente.

Las variables locales en los métodos pierden su alcance cuando el método que las ocupa
termina. A partir de ese momento esos métodos son elegibles para el recolector de
basura. Cada vez que el método vuelve a estar en el alcance del programa las variables
locales se vuelven a crear.

73
Tutorial para el examen de certificación: SCJP 1.2

Pregunta 1)

¿Cual de las siguientes líneas tiene la sintaxis correcta para sugerir que la JVM ejecute la
recolección de basura?

1) System.free();
2) System.setGarbageCollection();
3) System.out.gc();
4) System.gc();

Pregunta 2)

¿Qué código puedes escribir para asegurarte que las variables tipo int son recolectadas en
un punto particular en este código?

public class Rub{


int i=1;
int j=2;
int k=3;
public static void main(String argv[]){
Rub r = new Rub();
r.amethod();
}
public void amethod(){
i=0;
j=0;
k=0;
}
}

1) System.gc();
2) System.free();
3) Fijar el valor de cada variable int a null.
4) Ninguno de los anteriores.

Respuestas

Respuesta 1)

4) System.gc();

Respuesta 2)

4) Ninguno de los anteriores.

74
javaHispano. Tu comunidad, tu lenguaje.

Únicamente puedes sugerir la ejecución del recolector de basura, por consiguiente


no puedes estar seguro que se ejecutará en algún punto en particular de tu código.

Otras Fuentes para este tema


Jyothi Krishnan en
http://www.geocities.com/SiliconValley/Network/3693/obj_sec3.html#obj8

75
Tutorial para el examen de certificación: SCJP 1.2

Sección 4. Fundamentos del lenguaje.


Objetivo 1.
Identificar las declaraciones correctas para la construcción de paquetes, conocer la
sentencia import, la declaración de clases (todas las formas para incluir clases internas),
conocer la declaración e implementación de interfaces (por ejemplo
java.lang.Runnable u otra interfase descrita en el examen), declaración de métodos
(incluyendo el método main que se usa para comenzar la ejecución de una clase), las
declaraciones de variables e identificadores.

Nota sobre este objetivo


La frase de este objetivo es un poco extraña. Parece estar pidiéndote que entiendas donde,
cómo y por qué puedes usar la sentencia import y package, donde debes colocar la
declaración de una interface y las declaraciones de las variables.

La sentencia package
La palabra package implica una colección de clases, algo parecido a una librería. En el
uso, un paquete es un poco semejante a un directorio. Si pones una declaración de un
paquete en un archivo éste será sólo visible a otras clases en el mismo paquete. Puedes
poner un comentario antes de la declaración del paquete pero nada más. Puedes encontrar
preguntas del examen en donde pongan una sentencia import antes de la declaración del
paquete.

//Puedes colocar un comentario antes de la sentencia package


package MyPack;
public class MyPack{}

Lo siguiente causará un error:

import java.awt.*;
//Error: colocar una sentencia import antes de la declaración
//del paquete causará un error al compilar.
package MyPack;
public class MyPack{}

Si un archivo fuente tiene una sentencia package, ésta debe ponerse antes de
cualquier otra declaración aparte de los comentarios.

La sentencia package puede incluir la anotación punto para indicar la jerarquía del
paquete. Así el siguiente código compilará sin el error:

package myprogs.MyPack;

76
javaHispano. Tu comunidad, tu lenguaje.

public class MyPack{}

Recuerda que si no pones una sentencia package al inicio del archivo fuente, se
considerará que éste forma parte del paquete predefinido que corresponde al directorio
actual.

La sentencia import

La sentencia import debe ir después de cualquier sentencia package y antes de


cualquier otra línea de código. La sentencia import no puede ir dentro de las clases, ni
después de la declaración de la clase o en cualquier otra lugar.

La sentencia import te permite usar una clase directamente con su nombre en lugar de
especificarla totalmente incluyendo el nombre completo del paquete al que pertenece. Un
ejemplo de esto es que a la clase java.awt.Button normalmente se le referencia
simplemente como Button, pero para ello requieres haber puesto al inicio del archivo
fuente la siguiente línea:

import java.awt.*;

Toma en cuenta que aún usando la declaración completa de la clase no se afecta el


desempeño ni se cambia el tamaño del archivo .class generado.

Clases y la declaración de clases internas

Un archivo puede tener únicamente una clase con modificador public. Si intentas crear
un archivo con más de una clase pública el compilador te indicará un error específico. Un
archivo puede contener múltiples clases no públicas, pero ten presente que esto generara
distintos archivos .class separados por cada clase.

Las clases internas se introdujeron con el JDK 1.1 La idea es permitir la definición de una
clase dentro de otra, para que ésta pueda ser definida dentro de un método y para la
creación de clases internas anónimas. Esto tiene algunos efectos interesantes,
particularmente en la visibilidad.

Lo siguiente es un ejemplo sencillo de una clase interna:

class Outer{
class inner{}
}

Esto produce la generación de archivos .class con los nombres:

77
Tutorial para el examen de certificación: SCJP 1.2

Outer.class
Outer$Inner.class

La definición de la clase interna es sólo visible dentro del contexto de la existente clase
Exterior. Así el siguiente código causará un error cuando se compile:

class Outer{
class Inner{}
}

class Another{
public void amethod(){

Inner i = new Inner();


}

De modo que la clase Another no se podría crear, ya que, en ese contexto la clase
inner no existe. Ésta sólo puede existir en el contexto de una instancia de la clase
Outer. Así, el siguiente código se compilará sin problemas ya que sé esta instanciando la
clase Inner dentro del ámbito de la clase Outer.

class Outer{
public void mymethod(){
Inner i = new Inner();
}
public class Inner{}
}

Pero que pasa si el contexto de la instancia Outer no existe. Para entender mejor como
conseguir lo anterior, pensemos como podemos lograr el efecto anterior utilizando la
palabra clave this.

Podrías cambiar la línea que crea la instancia por lo siguiente:

Inner i = this.new Inner();

Así, si necesitas crear una instancia de la clase Inner en un método estático o en alguna
otra parte donde no tenga ámbito el objeto, puedes usar la palabra clave new como un
método que pertenece a una clase exterior.

class Outer{
public class Inner{}
}

78
javaHispano. Tu comunidad, tu lenguaje.

class another{
public void amethod(){
Outer.Inner i = new Outer().new Inner();
}

A pesar de mis locas explicaciones, encuentro poco intuitiva esta sintaxis y hasta yo me
olvido de ella cinco minutos después de aprendérmela. Es muy probable que encuentres
preguntas referentes a esto en el examen, así que préstale bastante atención.

Puedes acceder a una clase interna utilizando el siguiente código:

Outer.Inner i = new Outer().new Inner();

Uno de los beneficios de las clases internas es que una clase interna generalmente
consigue acceso a los campos la clase que lo contiene(o una externa)

Al contrario de una clase externa, una clase interna puede ser privada o estática. Los
examinadores pueden hacer preguntas molestas como "¿Puede una clase interna ser
estática o privada?". Haciendo estática una clase interna, ésta tiene algunos efectos
interesantes con la manera en que se tienen acceso a los campos o miembros de la clase
que la contiene. El efecto de hacer estáticos los recursos se refleja en que sólo hay una
instancia de cualquier variable, no importa cuántas instancias se creen de la clase externa.
En esta situación ¿Cómo puede la clase interna estática saber qué variables puede acceder
de su clase externa no estática?. Por supuesto la respuesta es que no lo puede saber, y así
una clase interna estática no puede acceder variables de instancia de la clase que la
contiene.

Por supuesto, los métodos de una clase interna estática pueden acceder a cualquier campo
o miembro estático de la clase que lo contiene pero siempre será únicamente a una sola
instancia de cualquiera de esos campos.

Clases internas declaradas dentro de métodos

Las clases internas se pueden crear dentro de los métodos. Esto es algo que las
herramientas de desarrollo de aplicaciones como JBuilder de Borland hacen
constantemente cuando generan un manejador de Eventos.

Aquí hay un ejemplo de dicho código generado automáticamente:

79
Tutorial para el examen de certificación: SCJP 1.2

buttonControl1.addMouseListener(new java.awt.event.MouseAdapter()
{
public void mouseClicked(MouseEvent e) {
buttonControl1_mouseClicked(e);
}
});

Fíjate en la palabra clave new que se encuentra justo después del primer paréntesis. Esta
indica que una clase interna anónima(sin nombre) está definiéndose dentro del método
addMouseListener. Esta clase normalmente podría definirse con un nombre que
podría hacerla más fácil de leer, pero cuando ese fragmento de código no se utiliza para
algún otro proceso en cualquier otra parte, darle un nombre no ayuda mucho.

Si creas tal código de manera manual, es fácil confundirte por el número de niveles de las
llaves y paréntesis. Observa cómo la estructura completa finaliza con punto y coma, ya
que es realmente ahí en donde finaliza la llamada al método.

Como podrías suponer una clase anónima no puede tener un constructor. Míralo de esa
manera, un constructor es un método sin valor de retorno y con el mismo nombre de la
clase. ¡Upss! Nosotros estamos hablando de clases sin nombres. Una clase anónima
puede heredar otra clase o implementar una única interface. Este límite peculiar no parece
ser tomado en cuenta en el examen.

Visibilidad de campos para clases definidas dentro de un método

Una clase definida dentro de un método puede acceder sólo a campos o miembros del
método que la contiene si éstos se han definido con el modificador final. Esto se debe a
que las variables definidas dentro de un método normalmente se consideran variables
automáticas; es decir, sólo existen mientras el método se está ejecutando. Los Campos o
miembros definidos dentro de una clase creada dentro de un método duran mas que el
método que la contiene.

Una clase definida dentro de un método solo puede acceder a campos con el
modificador final del método que la contiene

Debido que una variable con modificador final no puede ser cambiada por la JVM puedes
estar seguro que el valor permanecerá constante aun después de que el método exterior ha
dejado de ejecutarse. Es muy probable que encuentres preguntas referentes a esto en el
examen, incluso preguntas que cuestionen el estado de las variables pasadas como
parámetros al método.

80
javaHispano. Tu comunidad, tu lenguaje.

Creando una interface

Las interfaces son la manera en que Java maneja la ausencia de la herencia múltiple.
Curiosamente Visual Basic tiene la palabra reservada interface y maneja el concepto
de manera similar a Java. El tema de las interfaces es conocido en ocasiones como
programación por contacto. Una interface se utiliza a través de la palabra clave
implements. Así, una clase puede declararse de la siguiente manera:

class Malvern implements Hill,Well{


public
}

Pregunta 1)

Dado el siguiente código:

public class FinAc{


static int l = 4;
private int k=2;

public static void main(String argv[]){


FinAc a = new FinAc();
a.amethod();

}
public void amethod(){
final int i = 99;
int j = 6;
class CInMet{
public void mymethod(int q){
//Here
}//fin de mymethod
}//fin de CInMet

CInMet c = new CInMet();


c.mymethod(i);

81
Tutorial para el examen de certificación: SCJP 1.2

}//fin de amthod
}

¿Cuales de las siguientes variables son visibles en la línea marcada con el comentario
//Here?

1)l
2)k
3)i
4)j

Pregunta 2)

¿Cuales de los siguientes fragmentos de código compilarán correctamente?

1)
//A Comment
import java.awt.*;
class Base{};

2)
import java.awt.*;
package Spot;
class Base();

3)
//Another comment
package myprogs.MyPack;
public class MyPack{}

4)
class Base{}
import java.awt.*;
public class Tiny{}

Pregunta 3)

¿Cuales de las siguientes afirmaciones son verdaderas?

1)Una clase interna puede definirse como estática


2)Una clase interna no puede ser defina como privada
3)Una clase anónima puede tener sólo un constructor
4)Una clase interna puede heredar otra clase

82
javaHispano. Tu comunidad, tu lenguaje.

Pregunta 4)

Desde código que no tenga activa la referencia this, ¿Como puedes crear una instancia
de una clase interna?

1)Outer.Inner i = new Outer().new Inner();


2)Sin una referencia this una clase interna no puede ser creada
3)Outer.Inner i = Outer().new new Inner();
4)Outer i = Outer.new().Inner();
Respuestas

Respuesta 1)

1) l
2) k
3) i

Una clase definida dentro de un método solo puede ver campos con el modificador
final desde el método que la contiene. Sin embargo, también puede ver los campos de
la clase que contiene al método que la contiene a ella, incluyendo campos privados. El
campo j no se definió como final.

Respuesta 2)

1)
//A Comment
import java.awt.*;
class Base{};

3)
//Another comment
package myprogs.MyPack;
public class MyPack{}

La declaración de un paquete debe ser la primera línea de código en un archivo (aparte de


los comentarios). Una declaración import debe estar después de cualquier declaración
de un paquete y antes de cualquier otra línea de código.

Respuesta 3)

1)Una clase interna puede definirse como estática


4)Una clase interna puede heredar otra clase

Las clases anónimas no pueden tener un constructor. Las clases internas pueden definirse
como privadas.

Respuesta 4)

83
Tutorial para el examen de certificación: SCJP 1.2

1)Outer.Inner i = new Outer().new Inner();

Otras Fuentes para este tema:


El Tutorial de SUN
http://java.sun.com/docs/books/tutorial/java/more/nested.html

Richard Baldwin
http://www.Geocities.com/Athens/7077/Java094.htm
y también
http://www.Geocities.com/Athens/7077/Java095.htm

Jyothi Krishnan
http://www.geocities.com/SiliconValley/Network/3693/obj_sec4.html#obj9

Un Tutorial sobre paquetes


http://v2ma09.gsfc.nasa.gov/JavaPackages.html

Especificaciones sobre interfaces en Java


http://java.sun.com/docs/books/jls/html/9.doc.html#238680

84
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 2.
Declarar la correspondencia entre los valores del arreglo pasado como argumento al
método main y los argumentos de la línea de comandos.

Nota: Este tema por sí solo difícilmente amerita ser tomado como un objetivo.

Este objetivo puede sorprender al programador más experimentado en C/C++ ya que el


primer elemento del arreglo argv[] es la primera cadena después del nombre del
programa en la línea de comandos. Así si un programa se ejecutara como sigue:

java myprog myparm

El elemento argv[0] contendría "myparm". Si vienes de programar en C/C++ podrías


esperar que el contenido fuera "java". Java no contiene una opción equivalente a Option
Base de Visual Basic y, en consecuencia, los arreglos siempre empezarán desde el
elemento cero.

Veamos el siguiente código:

public class MyParm{


public static void main(String argv[]){
String s1 = argv[1];
System.out.println(s1);
}
}

He asignado el argumento 1 a un String sólo para resaltar que argv es un arreglo de


String's. Si ejecutas este programa de la manera siguiente:

java MyParm hello there

Se mostrará there, y no hello o MyParm

Pregunta 1)

85
Tutorial para el examen de certificación: SCJP 1.2

Dado el siguiente método main en una clase llamada cycle:

public static void main(String bicycle[]){


System.out.println(bicycle[0]);
}

y una llamada desde la línea de comandos como la siguiente:

java Cycle one two

¿Cuál será la salida?

1) Ninguna de estas opciones


2) Cycle
3) one
4) two

Pregunta 1)

¿Cómo puedes recuperar los valores pasados desde la línea comandos al método main?

1) usando el método System.getParms()


2) asignando un elemento del argumento a un String
3) asignando un elemento del argumento a un arreglo de caracteres
4) ninguna de estas opciones

Respuestas

Respuesta 1)

3) one

Respuesta 2)

2) asignando un elemento del argumento a un String

Otras Fuentes para este tema:


Este tema es cubierto en el tutorial de SUN en:
http://java.sun.com/docs/books/tutorial/essential/attributes/cmdLineArgs.html

86
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 3.

Identificar todas las palabras reservadas del lenguaje.

Nota en este objetivo: Puedes asimilar fácilmente este objetivo en base a aprender las
palabras reservadas frecuentemente menos utilizadas y asegurándote no tomar en cuenta
a "falsos friendsπ" de otros lenguajes que puedes llegar a saber, particularmente C/C++.
El examen pone énfasis especial en el reconocimiento de las palabras reservadas.

Reconocerás la mayoría de la palabras reservadas de Java conforme uses el lenguaje, pero


en el uso personal del lenguaje raramente utilizamos las excepciones, y las palabras
reservadas que podrían venir en el examen.

Ejemplos de las palabras reservadas más raramente utilizadas (indudablemente para un


principiante) son:

• volatile
• transient
• native

Palabras reservadas
abstract boolean break byte case catch
char class const * continue default do
double else extends final finally float
for goto * if implements import instanceof
int interface long native new null
package private protected public return short
static super switch synchronized this throw
throws transient try void volatile while

Las palabras con asteriscos son reservadas y actualmente no son utilizadas. Observa que
todas las palabras reservadas están en minúsculas, así for es una palabra reservada pero
FOR no la es. Hay un debate acerca de que si null es una palabra reservada, pero
sugiero que para los propósitos del examen asumas que si la es.

π
NT: El autor utiliza esa expresión para referirse a la confusión que en ocasiones produce la palabra friend,
la cual es palabra reservada en C++, pero no en Java.

87
Tutorial para el examen de certificación: SCJP 1.2

Pregunta 1)

¿Cuáles de las siguientes son palabras reservadas de Java?

1) double
2) Switch
3) then
4) instanceof

Pregunta 2)

¿Cuáles de las siguientes no son palabras reservadas de Java?

1)volatile
2)sizeOf
3)goto
4)try

Respuestas

Respuesta 1)

1) double
4) instanceof

Nota que la letra mayúscula S en switch hace que ésta no sea una palabra reservada y la
palabra then es parte de Visual Basic pero no de Java.

Respuesta 2)

2)sizeOf

88
javaHispano. Tu comunidad, tu lenguaje.

Esta es una palabra reservada en C/C++ para determinar el tamaño de un dato primitivo
para una plataforma en particular. Debido a que los datos primitivos tienen el mismo
tamaño en todas las plataformas en Java ésta palabra reservada no se necesita.

Otras Fuentes para este tema


Michael Thomas
http://www.michael-thomas.com/java/JCP_Keywords.htm

89
Tutorial para el examen de certificación: SCJP 1.2

Objetivo 4.
Conocer el efecto de usar una variable o un elemento de un arreglo de cualquier tipo
cuando no se le ha hecho alguna asignación explicita.

Variables

Podrías aprender a programar en Java sin realmente entender la importancia que


representa este objetivo, pero éste representa conocimiento valioso para el mundo real.
Esencialmente a una variable de nivel de clase siempre se le asignará un valor
predefinido y a una variable miembro (una variable contenida dentro de un método) no se
le asignará un valor predefinido. Si intentas acceder a una variable sin asignar generarás
un error. Por ejemplo:

class MyClass{
public static void main(String argv[]){
int p;
int j = 10;
j=p;
}
}

Este código producirá el siguiente error:

"error variable p might not have been assigned"

Esto puede verse como un cambio bienvenido de la tendencia de C/C++ de darle bastante
cuerda a una variable sin asignar dejando un valor arbitrario en p. Si p se hubiera
definido al nivel de clase se le habría asignado su valor predefinido y no se habría
generado algún error.

class MyClass{
static int p;
public static void main(String argv[]){
int j = 10;
j=p; System.out.println(j);
}
}

El valor predefinido para un entero es 0, así el código anterior mostrará 0.

El valor predefinido para los tipos de datos numéricos es cero, para un boolean es
false y una referencia a un objeto es el único tipo de datos que tiene como valor
predefinido null.

90
javaHispano. Tu comunidad, tu lenguaje.

Antes de la inicialización de los arreglos, donde quiera que sean creados,


estos siempre son fijados para contener sus valores predefinidos.

Arreglos

Aprender esta parte del objetivo requiere comprender una sencilla regla. El valor de los
elementos de un arreglo de cualquier tipo base siempre se inicializará con un valor
predefinido, dondequiera que se defina el arreglo. No importa si el arreglo se define
a nivel de clase o método, a los valores del arreglo siempre se le pondrán sus valores
predefinidos. Una pregunta que puedes hacerte es ¿Qué contendrá un elemento en
particular de un arreglo sin asignar?. A menos que el arreglo sea de objetos, la
respuesta será distinta de null.

Pregunta 1)
Dado el siguiente código, ¿Qué contendrá el elemento b[5]?

public class MyVal{


public static void main(String argv[]){
MyVal m = new MyVal();
m.amethod();
}

public void amethod(){


boolean b[] = new boolean[5];
}
}

1) 0
2) null

91
Tutorial para el examen de certificación: SCJP 1.2

3) ""
4) Ninguna de estas opciones

Pregunta 2)

Dado el siguiente código, ¿Qué contendrá el elemento 1 del arreglo mycon?

MyCon(){
int[] mycon= new int[5];
}

1) 0
2) null
3) ""
4) Ninguna de estas opciones

Pregunta 3)

¿Qué pasara cuando intentes compilar y ejecutar el siguiente código?

public class MyField{


int i=99;
public static void main(String argv[]){
MyField m = new MyField();
m.amethod();
}
void amethod(){
int i;
System.out.println(i);
}
}

1)Se mostrará 99
2)Se mostrará 0
3)Se generará un error al compilar
4)Se generará un error al ejecutar

Pregunta 4)

¿Qué pasara cuando intentes compilar y ejecutar el siguiente código?

public class MyField{

92
javaHispano. Tu comunidad, tu lenguaje.

String s;
public static void main(String argv[]){
MyField m = new MyField();
m.amethod();
}
void amethod(){
System.out.println(s);
}
}

1)Error al compilar: s no ha sido inicializada


2)Error al ejecutar: s no ha sido inicializada
3)Salida en blanco
4)Se mostrará null

Respuestas

Respuesta 1)

4) Ninguna de estas opciones

Atención en este punto. Los elementos de un arreglo comienzan a numerarse desde 0,


por consiguiente, para éste arreglo, no hay un elemento 5. Si intentas ejecutar:

System.out.println(b[5])

Generarás una excepción.

Respuesta 2)

1)0

Un constructor actúa de manera parecida a cualquier otro método; así, un arreglo de


enteros será inicializado conteniendo ceros dondequiera que sea creado.

Respuesta 3)

3)Se generará un error al compilar

Generarás un error al compilar el código indicando que la variable i no ha sido


inicializada, la variable de nivel de clase i es un caso extraño, ya que es ensombrecida
por su versión en el nivel del método. Las variables de nivel de método no obtienen
ninguna inicialización por omisión.

Respuesta 4)

4)Se mostrará null

93
Tutorial para el examen de certificación: SCJP 1.2

Una variable creada en el nivel de clase siempre tendrá un valor por omisión. El valor por
omisión para una referencia a un objeto es null y el método toString implícitamente
llamado con System.out.println mostrará null.

Otras Fuentes para este tema:


Este tema es cubierto ligeramente en el Tutorial de SUN en:
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/vars.htmll

Richard Baldwin cubre el tema en:


http://www.geocities.com/Athens/Acropolis/3797/Java020.htm#variables

Jyothi Krishnan en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec4.html#obj12

94
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 5.
Definir el rango de todos los tipos de datos primitivosφ, declarar valores literales para
Strings y todos los tipos primitivos usando todos los formatos permitidos, conocer las
bases numéricas y sus representaciones.

Nota en este objetivo

Éste es uno de los ligeramente molestos, pero bastante fácil, objetivos a cubrir. Puedes
escribir una gran cantidad de código Java sin conocer el rango de los tipos primitivos
pero familiarizarte con ellos no debe tomarte mucho tiempo. Ten cuidado con este tema
para que puedas usar todos los formatos, y no pases por alto el formato octal.

Tamaño de los tipos primitivos enteros

Cuando este objetivo pide el rango de los tipos de datos primitivos asumo que para
representarlo sólo se requiere el número 2 elevado a la potencia apropiada en lugar del
número que representa. En mi mente hay sólo tres tipos enteros a aprender ya que, en mi
experiencia basada en PC. El tamaño de un byte es intuitivo: 8 bits.

Rango de los primitivos Enteros

Nombre Tamaño Rango

byte 8 bit -27 to 2 7-1

short 16 bit -215 to 215-1

int 32 bit -231 to 231-1

long 64 bit -2 63 to 2 63-1

Declarando literales enteros

Hay tres maneras de declarar un literal entero. Como esperabas, por defecto, es un valor
decimal. Aquí están las opciones

φ
NT: Algunos documentos utilizan el termino “sencillos” o “básicos” en lugar de “primitivos”.

95
Tutorial para el examen de certificación: SCJP 1.2

Declarando 18 como un literal


entero
Decimal 18
022 (Cero no la
Octal
letra O)
Hexadecimal 0x12

Si compilas y ejecutas esta pequeña clase obtendrás en cada ocasión el valor 18.

public class Lit{


public static void main(String[] argv){
int i = 18;
int j = 022;//Version Octal: dos veces ocho mas dos
int k = 0x12;//Version Hex: una vez dieciséis mas dos
System.out.println(i);
System.out.println(j);
System.out.println(k);
}
}

Roberts y Heller describen 6 maneras de declarar literales enteros, ya que para Java la
letra X para la declaración de un hexadecimal extraordinariamente no es sensible a
mayúsculas, observa que no se utilizan las letras de la A a la F para la notación
hexadecimal. A mí me es mas más fácil recordar únicamente las tres maneras descritas
anteriormente y que las letras no son sensibles a mayúsculas.

Tamaño de los tipos primitivos de coma flotante


Los números de coma flotante son especimenes ligeramente extraños debido a que sus
cálculos pueden tener algunos resultados inesperados. Citando a Peter Van Linden "La
precisión exacta depende del número que se representa". Como compensación a esta
precisión variable logras conseguir casi jugar con números grandes más allá los que
puedas imaginar. Así una variable de tipo double puede almacenar un número como 17
seguido por 307 ceros. Un numero que sirve incluso para que puedas almacenar los
estados financieros de Bill Gates. (hasta que Linux alcance la dominación mundial total,
entonces un entero podrá hacer muy bien ese trabajo).

Rango de los tipo de


coma flotante
float 32 bit
double 64 bit

96
javaHispano. Tu comunidad, tu lenguaje.

Ten presente que el tipo de dato predefinido para un literal con un componente decimal
es un double y no un long. Esto es ligeramente confuso puesto que podrías pensar que
el tipo predefinido para un número de coma flotante debería ser un float. Puedes
encontrar preguntas en el examen similares a la siguiente:

¿Se compilará el siguiente código?

float i = 1.0;

Tu intuición debería decirte que esto debe compilarse sin problemas. Desgraciadamente
el examen no esta diseñado para probar su intuición. Esto causará un error en tiempo de
compilación ya que estas intentando asignar un double a un float. Puedes arreglar este
código de la manera siguiente:

float i = 1.0F;

o incluso:

float i = (float) 1.0;

Indicando tipos de datos con un literal sufijo

Como se mostró anteriormente puedes indicarle a Java que un literal numérico es de un


tipo de dato en particular asignándole un literal sufijo. Estos son los sufijos disponibles:

Sufijos para tipos


de datos
float F
long L
double D

Los tipos boolean y char

Los tipos de datos primitivos boolean y char son un poco curiosos. Si tienes
experiencia programando con C/C++ presta atención particularmente al tipo boolean y a
asegúrate de no traer contigo "falsos friends" de cualquiera de estos lenguajes. A un tipo
boolean no se le puede asignarse otro valor distinto de true o false. Los valores
true o false no corresponden al 0, al -1 o a algún otro número.

97
Tutorial para el examen de certificación: SCJP 1.2

Un dato de tipo boolean únicamente puede recibir los valores de true o false,
y no se le puede asignar un número como –1 o 0.

El tipo de dato primitivo char es el único tipo de dato primitivo sin signo. El tipo char
se usa para denotar un carácter Unicode. Unicode es un código alternativo al ASCII
que almacena caracteres en 2 bytes en lugar de 1 byte como lo hace el código ASCII.
Esto te permite representar 65K caracteres, qué aunque no es una cantidad
suficientemente grande para cubrir todas las escrituras del mundo, es mejor que los 255
caracteres que nos proporciona el código ASCII. La internacionalización es un tema
completo por si mismo, y el hecho de que puedas representar caracteres en chino o
Vietnamés, no significa que se desplegarán correctamente si tienes un sistema operativo
en inglés normal.

Un literal de tipo char se crea encerrando el carácter con comillas simples:

char a = 'z';

Nota que son comillas simples ‘ y no comillas dobles “.

Todo esto es funcional en mi pequeño mundo basado en el Ingles pero como Java es un
sistema mundial un char puede contener cualquiera de los caracteres disponible en el
sistema Unicode. Esto se hace usando cuatro dígitos hexadecimales precedidos por \u,
con la expresión completa encerrada con comillas simples.

Así, el espacio en blanco se representa de la siguiente manera:

char c = ‘\u0020’;

Si asignas un número sencillo a un char, éste será tomado como un carácter alfabético.
Así que el siguiente código mostrará la letra A(valor 65 del código ASCII) seguido de
una espacio en blanco.

public class MyChar{


public static void main(String argv[]){
char i = 65;
char c = '\u0020';
System.out.println(i);
System.out.println("This"+c+"Is a space");
}
}

98
javaHispano. Tu comunidad, tu lenguaje.

Declarando literales String

El tipo String no es un tipo de dato primitivo pero es tan importante que en ciertas
áreas Java lo trata como si lo fuera. Uno de estos rasgos es la habilidad de declarar
literales String en lugar de usar new para instanciar una copia de la clase.

Las literales String son bastante sinceras. Asegúrate de recordar que las literales
String son encerradas con comillas dobles mientras que un literal char utiliza comillas
simples.

Así:

String name = "James Bond"

Pregunta 1)

¿Cuáles de las siguientes líneas se compilarán correctamente?

1) float f=10f;
2) float f=10.1;
3) float f=10.1f;
4) byte b=10b;

Pregunta 2)

¿Cuáles de las siguientes líneas se compilarán correctamente?

1) short myshort=99S;
2) String name='Excellent tutorial Mr Green';
3) char c=17c;
4) int z=015;

Pregunta 3)

99
Tutorial para el examen de certificación: SCJP 1.2

¿Cuáles de las siguientes líneas se compilarán correctamente?

1) boolean b=-1;
2) boolean b2=false;
3)int i=019;
4) char c=99;

Respuestas

Respuesta 1)

1) float f=10f;

3) float f=10.1f;

Para la opción 4; No existe una literal b(byte), y la opción 2 causará un error al


compilarse debido a que el tipo de dato por omisión para un número con un componente
decimal es double.

Respuesta 2)

4)int z=015;

Las letras c y s no existen como indicadores literales y un String debe estar encerrado
por comillas dobles y no por comillas simples como en el ejemplo.

Respuesta 3)

2) boolean b2=false;
4) char c=99;

Te debe ser bastante obvio que la opción 1 es errónea, a un boolean únicamente se le


pueden asignar los valores true y false. La opción 3 es ligeramente más difícil de
detectar como errónea; ya que, esa es la manera correcta de declarar un literal octal; pero
no puedes usar el número 9 si estas en base 8 donde tienes números del 0 al 7. Quizá sean
un poco tramposas estas ultimas opciones.

Otras Fuentes para este tema:


Este tema es cubierto en el Tutorial de SUN en:
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/vars.html
(No encontraras mención alguna sobre las literales.)

100
javaHispano. Tu comunidad, tu lenguaje.

Richard Baldwin cubre este tema en:


http://www.Geocities.com/Athens/Acropolis/3797/Java020.htm#primitive types
(nuevamente no encontraras mención alguna sobre las literales.)

Jyothi Krishnan en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec4.html#obj13

Bruce Eckel's Thinking in Java


Capítulo 2 "Caso Especial: Tipos primitivos”
Capítulo 3 "Literales"

101
Tutorial para el examen de certificación: SCJP 1.2

Sección 5. Operadores y Asignaciones

Objetivo 1

Determinar el resultado de aplicar cualquier operador, incluyendo los operadores de


asignación y el operador instanceof, sobre operandos de cualquier tipo de clase,
dependiendo de su alcance, accesibilidad, o de la combinación de estos.

El operador instanceof

El operador instanceof es una bestia extraña, desde mi punto de vista debería ser un
método en lugar de un operador. Probablemente has escrito bastante código con Java y no
has tenido la necesidad de usarlo, pero para propósitos del examen necesitas conocerlo.
Este operador retorna un valor booleano como resultado a una prueba sobre un tipo de
clase en tiempo de ejecución. Y efectivamente, como estas pensando, se usa para
preguntar:

¿Es esta_clase instanciade esta_otra_clase?

Si lo utilizas en casos triviales como el siguiente, quizá no le veas mucha utilidad:


public class InOf {
public static void main(String argv[]){
InOf i = new InOf();
if(i instanceof InOf){
System.out.println("It's an instance of InOf");
}//End if
}//End of main
}

Como habrás deducido el resultado será:

It's an instance of InOf

Sin embargo, pueden surgir situaciones donde únicamente tienes acceso a una referencia
de un objeto, el cual se refiere a algo que esta más arriba o más abajo en la jerarquía de
clases del programa. Así puedes tener un método que tome como parámetro un
componente que puede referirse a un botón, a una etiqueta o a cualquier otra cosa. En
estas circunstancias, el operador instanceof se usa para examinar el tipo del objeto,
realizar una comparación y una conversión y así llamar al método más apropiado. El
siguiente código ilustra un ejemplo de esto:

import java.awt.*;

102
javaHispano. Tu comunidad, tu lenguaje.

public class InOfComp {


public static void main(String argv[]){

}//End of main

public void mymethod(Component c){


if( c instanceof Button){
Button bc = (Button) c;
bc.setLabel("Hello");
}else
if (c instanceof Label){
Label lc = (Label) c;
lc.setText("Hello");
}
}//End of mymethod

Si en tiempo de compilación la examinacion del tipo de la clase y la conversión forzada


no fueran realizadas, los métodos setLabel y setText no estarían disponibles.
Observa que el operador instanceof se aplica a los nombres de las clases no a una
referencia de un objeto para una clase.

El operador +

Como esperabas, el operador + adiciona 2 números entre si. Así la siguiente línea de
código
mostrará 10:

int p=5;
int q=5;
System.out.println(p+q);

El operador + es un ejemplo raro de la sobrecarga de operadores en Java. los


programadores en C++ están acostumbrados a poder sobrecargar operadores para que
estos signifiquen cualquier cosa que ellos definan. Esta facilidad no está disponible para
un programador en Java, sin embargo esta opción esta disponible para los Strings, ya
que el signo mas(+) se sobrescribe para ofrecer la concatenación de Strings. De esta
manera el siguiente código sí se compilará:

String s = "One";
String s2 = "Two"
String s3 = "";
s3 = s+s2;
System.out.println(s3);

103
Tutorial para el examen de certificación: SCJP 1.2

El resultado será "OneTwo", observa que no hay espacios entre las dos cadenas unidas.

Bajo ciertas circunstancias Java realiza una llamada implícita el método toString.
Este
método, como su nombre lo dice, intenta convertir a un String a el objeto que lo llama.
Para un entero con valor 10, la llamada a toString retornara la cadena "10".

Lo anterior se aprecia mejor en el siguiente código

int p = 10;
String s = "Two";
String s2 = "";
s2 = s + p;
System.out.printlns(s2);

el resultado será:

Two10

Recuerda que para los Strings, únicamente el operador + esta sobrecargado. Si


intentas utilizar sobre un String los operadores división y menos(/,-) causaras un
error.

Asignando variables primitivas de tipos diferentes

Un booleano única y exclusivamente puede recibir otro valor de tipo booleano. Para los
programadores C/C++, recuerden que esto significa que a un booleano no se le puede
asignar -1 o 0, ya que en Java un booleano no es substituible por el numero cero o un
valor
distinto de cero.

Con esta principal excepción en el tipo de datos boolean, el principio general para
entender este objetivo esta en saber que las conversiones por "ensanchamiento" están
permitidas en Java, siempre y cuando no impliquen exactitud. Por ensanchamiento quiero
decir que una variable como un byte que ocupa 1 byte (ocho bits) puede asignarse a una
variable que ocupa más bits como por ejemplo un int.

Sin embargo si intentas asignar un int a un byte conseguirás un error en tiempo de


compilación:

byte b= 10;
int i = 0;
b = i;

104
javaHispano. Tu comunidad, tu lenguaje.

Los datos primitivos pueden ser asignados a tipos de datos mas


"anchos", un booleano únicamente puede ser asignado a otro booleano.

Como esperabas, no puedes asignar datos primitivos a objetos y viceversa. Así, el


siguiente
código no es valido:

int j=0;
Integer k = new Integer(99);
j=k; //Asignacion ilegal de un objeto un tipo primitivo.

Una diferencia importante entre la asignación de objetos y la asignación de tipos


primitivos, es que los tipos primitivos son revisados en tiempo de compilación mientras
que los objetos son revisados en tiempo de ejecución. Esto se cubrirá mas adelante ya que
tiene implicaciones importantes cuando un objeto no esta completamente resuelto en
tiempo de compilación.

Por supuesto, puedes realizar una conversión forzada para hacer que una variable
se ajuste a un tipo de datos mas estrecho, Esto a menudo no es aconsejable ya que el
resultado perderá precisión, pero es valido si realmente lo quieres hacer. Java utiliza la
convención de C/C++ encerrando entre paréntesis () el tipo de datos al que se quiere
convertir. Por lo tanto el siguiente código se compilara y ejecutara sin problemas:

public class Mc{


public static void main(String argv[]){
byte b=0;
int i = 5000;
b = (byte) i;
System.out.println(b);
}
}

el resultado es

-120

Posiblemente no es un valor que te sea muy útil.

Asignando referencias de objetos de diferentes tipos.

Cuando asignamos referencias de objetos, otra regla general es que puedes realizar la
asignación de abajo hacia arriba en la jerarquía de clases, pero no de arriba hacia abajo.
Puedes ver esto de la siguiente manera. Si tu asignas una instancia de una clase hija a la

105
Tutorial para el examen de certificación: SCJP 1.2

clase Base, Java sabrá qué métodos están en la clase hija. Sin embargo una clase hija
puede tener métodos adicionales de los que le proporciona la clase Base. Puedes
solucionar este problema usando la conversión forzada.

Las referencias de objetos se asignan hacia arriba en la jerarquía de


clases.

El siguiente ejemplo muestra que ocurre cuando fuerzas la asignación de una referencia
de un objeto hacia una clase de jerarquía superior:

class Base{}

public class ObRef extends Base{


public static void main(String argv[]){
ObRef o = new ObRef();
Base b = new Base();
b=o;//Esta linea se compilara sin error
/*o=b; Esto debe causar un error
indicando que se requiere una
conversion forzada para asignar una
referencia de Base a ObRef */

}
}

Operadores de desplazamiento de bits.

Odio un poco esto de trabajar con desplazamientos de bits. Ya que implica que llenes tu
mente con una capacidad no intuitiva que es trabajar con números infinitamente
pequeños, números que un programador quizá nunca utilizara. Pero debido a que todas
las razones para aprenderlo son por que pueden aparecer en el examen, es mejor tratar el
tema, pues es poco probable que lo aprendas de otra manera. El resultado de usar estos
operadores puede sorprenderte.

Para entenderlos tienes que tener un pensamiento binario bastante fluido, por ejemplo
conocer el valor de un bit en cada posición:

32, 16, 8, 4, 2, 1

Los programadores C/C++, pueden estar tranquilos ya que la manera de trabajar del
operador de desplazamiento de bits en Java es menos ambigua que en C/C++. En C/C++
el desplazamiento hacia la derecha puede ser con signo o sin signo dependiendo de la
implementación del compilador. Si vienes de programar con Visual Basic, bienvenido a
la programación de bajo nivel.

106
javaHispano. Tu comunidad, tu lenguaje.

Observa que el objetivo únicamente pide que comprendas el resultado de aplicar estos
operadores sobre valores de tipo int. Esto es también aplicable a un byte o a un
short, particularmente si el valor es negativo, ya que se puede tener algunos resultados
demasiado inesperados.

Operadores de desplazamiento con signo << y >>

Los operadores de desplazamiento a la derecha y a la izquierda mueven el patrón de bits


hacia la derecha o hacia la izquierda y dejan solo al bit de signo del número.

Para números positivos los resultados son bastante predecibles. Así el desplazamiento
con signo para números positivos da los siguientes resultados:

int x = 14;
int y = 0;
y = x >>2;
System.out.println(y);

El resultado será 3,se pierde un bit y el resto del patrón de bits se inclina a la derecha

int x = 14;
int y = 0;
y = x <<2;
System.out.println(y);

El resultado será 56

De manera que, ¿Qué esperarías obtener al realizar un desplazamiento a la izquierda a un


numero negativo? Podrías esperar el mismo resultado obtenido al desplazar a la derecha
un número positivo excepto que el resultado mantiene el signo negativo. Si desplazamos
4 posiciones, lo que sucede es que cada una de las posiciones, debido al moviendo de los
otros bits, toman el valor del bit más significativo (el bit de signo). El efecto de esto es
que cada desplazamiento divide/multiplica el número negativo por dos. Esto te será fácil
de entender hasta que te des cuenta de las implicaciones del almacenamiento de números
binarios a través del complemento a dos.

El complemento a dos funciona un poco como el odómetro físico que se encuentra en el


tablero de los coches. Imagina que lo "rebobinas" hasta cero y después pasas a números
negativos. El primer número que obtendrías no sería 1, sería uno por debajo del máximo
que pudieras representar con las ruedecillas disponibles. Si esto te suena improbable
ejecuta la calculadora de Windows, ponla en modo científico, introduce un número
negativo y después pasa a modo binario. Esto te mostrará el patrón de bits del número
que hayas introducido.

107
Tutorial para el examen de certificación: SCJP 1.2

Si toda esta charla sobre patrones de bits y representación en complemento a dos "hace
que tu cabeza heche humo", podrías preferir pensar el desplazamiento de bits como un
proceso repetitivo de multiplicación o división por dos. Esta aproximación funciona bien
hasta que empiezas a desplazar un numero negativo a la derecha, de modo que pierde bits
del lado derecho.

Desplazamiento sin signo a la derecha >>>

El desplazamiento sin signo a la derecha >>> realiza un desplazamiento sin tomar en


cuenta el bit del signo. Así, en un int, los 32 bits son desplazados el numero de veces
que se le indique al operador y son rellenados los espacios de la izquierda con ceros. De
tal manera que esto da el efecto de convertir un número negativo a positivo Este
desplazamiento puede darnos algunos resultados muy raros. Veamos la siguiente
sentencia:

System.out.println(-1 >>>1);

El resultado es el siguiente:

2147483647

El examen probablemente no te pedirá que des el resultado exacto pero podría darle
algunas alternativas como 0, -1, etc. y tendrás que elegir el resultado mas aproximado.

¿Cual crees que sea el resultado para la siguiente línea de código?

System.out.println(-1 >>> 32);

Si acabas de leer que el deslazamiento sin signo no toma en cuenta el bit del signo, el
resultado de la línea anterior, que es -1, puede ser una sorpresa. La razón es que el
modulo 32 se realiza sobre el operando antes del desplazamiento. Así, si divides 32 entre
32 obtienes 0 y si realizas un desplazamiento sin signo de cero lugares hacia la derecha
tendrás todavía como valor -1. No deseches esto como si fuera una peculiaridad
irrelevante ya que puede venir en el examen.

He creado un applet que te permite probar varias operaciones de desplazamiento y ver


los resultados tanto en decimal como el patrón de bits. También se incluye el código para
que veas como trabaja, puedes revisarlo en:

http://www.jchq.net/applets/BitShift/BitShiftAr.html

Aquí hay una imagen que muestra el applet en funcionamiento.

Applet BitShift

108
javaHispano. Tu comunidad, tu lenguaje.

Pregunta 1)

Dadas las siguientes clases:

interface IFace{}
class CFace implements IFace{}
class Base{}

public class ObRef extends Base{


public static void main(String argv[]){
ObRef ob = new ObRef();
Base b = new Base();
Object o1 = new Object();
IFace o2 = new CFace();
}
}

¿Cuales de las siguientes líneas son válidas?

1) o1=o2;
2) b=ob;

109
Tutorial para el examen de certificación: SCJP 1.2

3) ob=b;
4) o1=b;

Pregunta 2)
Dadas las siguientes declaraciones:

String s = "Hello";
long l = 99;
double d = 1.11;
int i = 1;
int j = 0;

¿Cuales de las siguientes líneas compilaran sin error?

1) j=i <<s;
2) j=i<<j;
3) j=i<<d;
4) j=i<<l;

Pregunta 3)

Dadas las siguientes variables:

char c = 'c';
int i = 10;
double d = 10;
long l = 1;
String s = "Hello";

¿Cuales de las siguientes líneas compilaran sin error?

1) c=c+i;
2) s+=i;
3) i+=s;
4) c+=s;

Pregunta 4)

¿Cual será el resultado de la siguiente sentencia?

System.out.println(-1 >>>1);

1) 0
2) -1
3) 1

110
javaHispano. Tu comunidad, tu lenguaje.

4) 2147483647

Pregunta 5)

¿Cual será el resultado de la siguiente sentencia?

System.out.println(1 <<32);

1) 1
2) -1
3) 32
4)-2147483648

Pregunta 6)

¿Cuales de las siguientes sentencias son validas?

1) System.out.println(1+1);
2) int i= 2+'2';
3) String s= "on"+'one';
4) byte b=255;

Respuestas

Respuesta 1)

1)o1=o2;
2)b=ob;
4)o1=b;

Respuesta 2)

2)j= i<<j;
4)j=i<<l;

Respuesta 3)

2)s+=i;

Respuesta 4)

4) 2147483647

Aún y cuando no logres grabarte este numero, únicamente entendiendo al desplazamiento


sin signo a la derecha te puedes dar cuenta que todas las otras opciones no son correctas.

Respuesta 5)

111
Tutorial para el examen de certificación: SCJP 1.2

1) 1

Con el desplazamiento a la izquierda, los bits son "envueltos alrededor" del patrón de
bits.
Así, el resultado de:

System.out.println(1 <<31);

Será:

-2147483648

Respuesta 6)

1) System.out.println(1+1);
2) int i= 2+'2';

La opción 3 no es valida, ya que las comillas simples sirven para indicar un solo caracter
constante y no a una cadena. La opción 4 no compilara ya que el valor 255 esta fuera del
rango de un byte.

Otras Fuentes para este tema:


El tutorial de Sun
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/operators.html
No encontré nada relacionado con el operador instanceof

Richard Baldwin
http://home.att.net/~baldwin.dick/Intro/Java022.htm#bitwiseoperations
No encontré nada relacionado con el operador instanceof

Jyothi Krishnan cubre este tema en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec5.html#obj15

112
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 2.

Determinar el resultado de aplicar el método booleano equals(Object) sobre Objetos,


y cualquier combinación de las clases java.lang.String, java.lang.Boolean y
java.lang.Object.

Diferencia entre el método equals y el operador = =

El método equals puede verse como la realización de una comparación profunda del
valor de un objeto, por el contrario el operador = = realiza una comparación poco
profunda. El método equals compara lo que un objeto apunta en lugar del apuntador en
si (esto si consideramos que java tiene punteros ).

Usando el método equals con Strings

El método equals retorna un valor primitivo de tipo boolean. Esto significa que se
puede usar para manejar sentencias if, while u otra sentencia de enciclamiento. Puede
usarse también en lugar del operador = = con una primitiva. La utilización del método
equals y el operador = = tiene extraños efectos laterales cuando se usa para comparar
Strings. Esta es una de las ocasiones en donde la naturaleza inmutable de los Strings,
y la manera en que java maneja esta característica, puede crearte confusión.

Existen 2 maneras para crear un String en Java. Una de ellas implica la utilización del
operador new. Así, normalmente un String se crea de la siguiente manera:

String s = new String("Hello");

La otra manera, ligeramente más corta, es la siguiente:

String s = "GoodBye";

Generalmente la diferencia entre estas dos maneras de crear un String es mínima, pero
en el examen pueden haber preguntas que te exijan reconocer muy bien esta diferencia.

La creación de 2 cadenas con la misma secuencia de letras sin ocupar la palabra clave
new creara 2 apuntadores a la misma cadena en el pool de Strings de Java. El pool
de Strings es la manera en que Java mantiene los recursos. Veamos lo siguiente para
comprender mejor lo anterior:

String s = "Hello";
String s2 = "Hello";
if (s = = s2){

113
Tutorial para el examen de certificación: SCJP 1.2

System.out.println("Equal without new operator");


}

String t = new String("Hello");


String u = new String("Hello");
if (t == u){
System.out.println("Equal with new operator");
}

Tomando en cuenta lo que vimos en el objetivo anterior, esperarías que el primer mensaje
"Equal without new operator", nunca se mostrara ya que s y s2 son objetos
distintos, y además el operador = = examina lo que apunta a un objeto, no su valor. Sin
embargo, debido a la manera en que Java maneja los recursos con la re-utilización de
cadenas idénticas que son creadas sin el operador new, s y s2 tiene la misma "direccion"
y en consecuencia el código mostrará el mensaje:

"Equal without new operator"

Por otro lado, en el segundo par de Strings t y u, el operador new fuerza a Java a crear
cadenas separadas, es decir, dos objetos distintos. Y debido a que el operador = =
únicamente compara la dirección del objeto, y no su valor, t y u tienen diferentes
direcciones y así el mensaje "Equal with new operator" nunca se mostrará.

El método equals aplicado a Strings, sin importar la manera en que


fueron creadas, ejecuta una comparación caracter a caracter.

La manera en que trabaja el pool de String y la diferencia entre usar el operador = = y


el método equals no es muy obvio, particularmente si tienes antecedentes de programar
con Visual Basic. La mejor manera de comprender esto es creando algunos ejemplos por
ti mismo y viendo como es que trabajan. Prueba permutando cadenas idénticas creadas
con y sin el operador new.

Usando el método equals con la Clase Boolean

El requerimiento para comprender el uso del operador equals sobre


java.lang.Boolean es una confusión potencial. Boolean es un objeto envolvente
para la primitiva boolean

De acuerdo a la documentación del JDK el método equals en la clase Boolean:

"Retorna true si y solo si el argumento que recibe es distinto de null y si el objeto


Boolean que recibe tiene el mismo valor booleano que éste objeto"

114
javaHispano. Tu comunidad, tu lenguaje.

Ejemplo:

Boolean b1 = new Boolean(true);


Boolean b2 = new Boolean(true);
if(b1.equals(b2)){
System.out.println("We are equal");
}

Como un tema aparte sobre el uso de boolean y Boolean, una vez que te familiarices
con la sentencia if en Java te darás cuenta que no puedes realizar la conversión implícita
tan apreciada por los programadores C/C++. Esa conversión es del tipo:

int x =1;
if(x){
//realiza algo, pero no en Java
}

Esto no funcionara en Java porque el parámetro para la sentencia if debe ser una
evaluación booleana, ya que Java no tiene el concepto de C/C++ en donde cualquier valor
no nulo se considera verdadero. Sin embargo puedes realizar lo siguiente en Java :

boolean b1=true;
if(b1){
//do something in java
}

Aunque esta es una practica de programación bastante mala es sintácticamente correcta,


ya que el parámetro para la sentencia if es un booleano.

Usando el método equals con objetos

Debido al diseño fundamental de Java una instancia de cualquier clase es también una
instancia de la clase java.lang.Object. Examinaremos esto utilizando el método
toString. Para la clase Object, el método toString simplemente retorna la dirección
de memoria. Así el resultado es el equivalente de ejecutar una comparación con el
operador = =. Como Java no esta diseñado para manipular direcciones de memoria o
apuntadores, ésta no es una operación particularmente útil.

Veamos el siguiente ejemplo:

public class MyParm{


public static void main(String argv[]){
Object m1 = new Object();
Object m2 = new Object();
System.out.println(m1);

115
Tutorial para el examen de certificación: SCJP 1.2

System.out.println(m2);

if (m1.equals(m2)){
System.out.println("Equals");
}else{
System.out.println("Not Equals");
}
}

Si intentas compilar y ejecutar lo anterior, obtendrás algo similar a lo siguiente:

java.lang.Object@16c80b
java.lang.Object@16c80a
Not Equals

Estos valores son direcciones de memoria , y probablemente no tienen nada que ver con
lo que tu necesitas.

Pregunta 1)
¿Que pasará cuando intentes compilar y ejecutar el siguiente código?

public class MyParm{


public static void main(String argv[]){

String s1= "One";


String s2 = "One";
if(s1.equals(s2)){
System.out.println("String equals");
}
boolean b1 = true;
boolean b2 = true;
if(b1.equals(b2)){
System.out.println("true");
}
}
}

116
javaHispano. Tu comunidad, tu lenguaje.

1)Error al compilar
2)No se mostrará ningún mensaje
3)Se mostrará únicamente el mensaje "String equals"
4)Se mostrará el mensaje "String equals", seguido de "true"

Pregunta 2)
¿Que pasará cuando intentes compilar y ejecutar el siguiente código?

String s1= "One";


String s2 = new String("One");
if(s1.equals(s2)){
System.out.println("String equals");
}

Boolean b1 = new Boolean(true);


Boolean b2 = new Boolean(true);
if(b1==b2){
System.out.println("Boolean Equals");
}

1)Error al compilar
2)Se mostrará únicamente "String equals"
3)Se mostrará "String equals" seguido de "Boolean Equals"
4)Se mostrará únicamente "Boolean Equals"

Pregunta 3)
¿Cuál es el resultado de intentar compilar y ejecutar el siguiente código?

Object o1 = new Object();


Object o2 = new Object();
o1=o2;
if(o1.equals(o2))
System.out.println("Equals");

1)Error al compilar
2)Mostrará "Equals"
3)No mostrará nada
4)Error al ejecutarse

117
Tutorial para el examen de certificación: SCJP 1.2

Respuestas

Respuesta 1)

1)Error al compilar

la línea b1.equals causará un error debido a que b1 es un valor primitivo y los valores
primitivos no tienen métodos. Si b1 hubiera sido creado son la clase Boolean entonces
si podrías ocupar el método equals.

Respuesta 2)

2)Se mostrará únicamente "String equals"

Probar una instancia de la clase Boolean con el operador = = únicamente examina la


dirección de memoria, no el valor de la instancia.

Respuesta 3)

2)Mostrará "Equals"

Debido a que una instancia de Object a sido asignada a la otra en la línea:

o1=o2

Estas instancias apuntan ahora a la misma dirección de memoria y en consecuencia, la


aplicación del método equals retornará verdadero.

Otras Fuentes para este tema


Jyothi Krishnan cubre este tema en
http://www.geocities.com/SiliconValley/Network/3693/obj_sec5.html#obj16

Michael Thomas
http://www.michael-thomas.com/java/JCP_Operators.htm#equals()

118
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 3.
En una expresión que involucre a los operadores &,|,&&,||, y variables, conocer el estado
de los valores que son evaluados con estos operadores y el valor de la expresión.

Es fácil olvidarse cuales son los símbolos que significan una operación lógica y cuales
significan operaciones a nivel de bits, asegúrate de reconocer la diferencia para el
examen.
Si eres nuevo con el uso de estos operadores vale la pena que te asegures no confundirte
con los operadores a nivel de bits y los operadores lógicos.

El efecto corto circuito con los operadores lógicos.

Los operadores lógicos (&&, ||) tienen un ligero efecto peculiar en una operación lógica
llamado "corto circuito”, como ocurre de manera similar, en C/C++. Esto quizá te pueda
sorprender si vienes de programar con Visual Basic ya que Visual Basic evalúa todos los
operandos. En Java esto tiene sentido si consideras que en una operación AND, si el
primer operando es falso ya no es necesario evaluar el segundo operando, el resultado
final será, con certeza, falso. Lo mismo ocurre con el operador lógico OR, si el primer
operando ha resultado verdadero, el cálculo global será verdadero ya que sólo un
operando del OR debe retorna verdadero para que el resultado final sea verdadero. Esto
puede traer código un efecto especial con esos cálculos reducidos que dependen de
efectos laterales.

Veamos el siguiente ejemplo:

public class MyClass1{


public static void main(String argv[]){
int Output=10;
boolean b1 = false;
if((b1==true) && ((Output+=10)==20))
{
System.out.println("We are equal "+Output);
}else
{
System.out.println("Not equal! "+Output);
}
}
}

El resultado de este código será "Not equal 10". Esto muestra que la operación
Ouput+=10 jamás será realizada debido a que el proceso se detiene después de que se
evalúa la primera operación, debido a que retorna falso, y al estar aplicando el operador

119
Tutorial para el examen de certificación: SCJP 1.2

AND (&&) ya no es necesario evaluar el resto de la expresión, pues el resultado será


falso. Si cambias el valor de b1 a verdadero, la operación se realizará y el resultado será
el que esperabas: "We are equal 20".

Esto a veces puede ser conveniente cuando realmente no quieras procesar otras
operaciones si una de ellas retorna falso, pero puede tener un efecto lateral inesperado si
no estás completamente familiarizado con el uso de estos operadores.

Operadores a nivel de bits.

Los operadores | y & se aplican para realizar operaciones AND y OR a nivel de bits.
Puedes encontrarte preguntas en el examen que te den números en decimal y te pidan que
realices operaciones AND o OR a nivel de bits. Para hacer esto, necesitas familiarizarte
con la conversión de números decimales a binarios y conocer que ocurre con el patrón de
bits.

Este es un ejemplo típico

¿Cuál es el resultado de la siguiente operación?

3|4

El patrón binario para el decimal 3 es 11, el patrón binario para 4 es 100, para realizar
una operación OR a nivel de bits, cada bit es comparado con el bit que se encuentra en la
misma posición del otro número. Si alguno de los bits es 1 el bit del numero resultante,
en la posición que se esta comparando, es también 1. Así para esta operación el resultado
será:

011
100
------
111

y 111 es 7 en decimal.

Los objetivos no especifican que conozcas la operación XOR a nivel de bits. realizada
con el operador ˆ.

Pensando en binario

Si no te siente muy cómodo pensando en binario (yo me siento mucho mas cómodo
pensando en decimal), puedes querer hacer algunos ejercicios para ayudarte a dominar
este tema y también el relacionado con los operadores de desplazamiento de bits. Si estás

120
javaHispano. Tu comunidad, tu lenguaje.

ejecutando Windows puedes encontrar útil usar la calculadora que proporciona este
sistema operativo en modo científico. Para hacer esto solo elige la opción Ver y cambiar
del modo Estándar predefinido al modo científico. En modo científico puedes cambiar
entre ver los números en formato decimal y binario, esto despliega el patrón de bits de los
números.

Y si lo prefieres puedes realizar un programa que muestre el patrón de bits de un numero,


utilizando la clase Integer, he aquí un pequeño programa que muestra un ejemplo:

public class BinDec{


public static void main(String argv[]){
System.out.println(Integer.parseInt("100",2));
System.out.println(Integer.toString(64,2));
}
}

Si lo compilas y ejecutas este será el resultado:

4
1000000

Observa que el programa convierte el patrón de bits 100 en su equivalente en decimal,


que es 4; y convierte el decimal 64 en su patrón de bits equivalente.

Pregunta 1)
¿Que pasará cuando intentes compilar y ejecutar el siguiente código?

int Output=10;
boolean b1 = false;
if((b1= =true) && ((Output+=10)==20)){
System.out.println("We are equal "+Output);
}else{
System.out.println("Not equal! "+Output);
}

1)Error al compilar, por intentar realizar una comparación binaria sobre tipos de datos
lógicos
2)Se compilara y mostrará la cadena "We are equal 10"

121
Tutorial para el examen de certificación: SCJP 1.2

3)Se compilara y mostrará la cadena "Not equal! 20"


4)Se compilara y mostrará la cadena "Not equal! 10"

Pregunta 2)
Qué mostrará la siguiente línea de código

System.out.println(010|4);

1) 14
2) 0
3) 6
4) 12

Pregunta 3)

Cuales de los siguientes fragmentos de código se compilara sin errores

1)
int i=10;
int j = 4;
System.out.println(i||j);

2)
int i=10;
int j = 4;
System.out.println(i|j);

3)
boolean b1=true;
boolean b2=true;
System.out.println(b1|b2);

4)
boolean b1=true;
boolean b2=true;
System.out.println(b1||b2);

Respuestas)

Respuesta 1
4)Se compilara y mostrará la cadena "Not equal! 10"

Respuesta 2)

122
javaHispano. Tu comunidad, tu lenguaje.

4)12

La respuesta a esta pregunta requiere que conozcas la notación octal, el cero que antecede
al primer numero indica que dicho número esta en notación octal, 010 es la notación octal
para el numero 8 decimal.

Así, la instrucción:
System.out.println(010|4)
es equivalente a:
System.out.println(8|4);

que en binario es:

1000
0100
-----
1100
y 1100 en decimal es 12

Repuesta 3)

2,3,4

La opción 1 no compilara ya que estas intentando ejecutar una aplicación OR lógica


sobre tipos enteros. Y una operación lógica solo se puede realizar con argumentos de
tipo boolean.

Otras Fuentes para este tema


Tutorial de Sun:
http://java.sun.com/docs/books/tutorial/java/nutsandbolts/operators.html

Richard Baldwin
http://home.att.net/~baldwin.dick/Intro/Java022f.htm

123
Tutorial para el examen de certificación: SCJP 1.2

Objetivo 4

Determinar los efectos sobre los objetos y los valores primitivos al pasarlos como
variables en métodos al aplicarles asignaciones u otras modificaciones dentro del método.

Nota sobre este objetivo

El objetivo parece estarte pidiendo que entiendas lo que ocurre cuando pasas un valor a
un método. Si el código dentro del método modifica el valor de la variable, ¿El cambio es
visible aun fuera del método?

Si vienes de programar con C/C++ estarás familiarizado con el concepto "paso de


parámetros por valor" y "paso de parámetros por referencia" con el operador &. En java
no hay tal opción ya que todo es pasado por valor. Sin embargo esto no siempre es así. Si
pasas un objeto este es una referencia a un objeto y no puedes manipular directamente
una referencia a un objeto.

Así, si manipulas un campo de un objeto que se pasa a un método, el campo se


comportara como si lo hubieras pasado por referencia (esto quiere decir que cualquier
cambio mantendrá su efecto aún después de terminada la llamada al método).

Referencias de Objetos como parámetros de métodos.

Veamos el siguiente ejemplo:

class ValHold{
public int i = 10;
}
public class ObParm{
public static void main(String argv[]){
ObParm o = new ObParm();
o.amethod();
}
public void amethod(){
ValHold v = new ValHold();
v.i=10;
System.out.println("Before another = "+ v.i);
another(v);
System.out.println("After another = "+ v.i);
}//End of amethod
public void another(ValHold v){
v.i = 20;
System.out.println("In another = "+ v.i);
}//End of another

124
javaHispano. Tu comunidad, tu lenguaje.

El resultado será:

Before another = 10
In another = 20
After another = 20

Observa como el valor de la variable i ha sido modificado. Si java siempre pasa por
valor, ¿Cómo se ha modificado? Bueno, el método recibió una copia del manejador o
referencia del objeto pero esa referencia actúa como un apuntador al valor real del objeto
y las modificaciones se reflejan en los campos a los que apunta. Esto es parecido a la des-
referenciación automática de punteros en C/C++.

Primitivas como parámetros de métodos

Cuando pasas valores primitivos a métodos, estos pasan por valor. El método obtiene su
propia copia para utilizarla y en consecuencia, cualquier modificación no se refleja fuera
del método. Veamos el siguiente ejemplo:

public class Parm{


public static void main(String argv[]){
Parm p = new Parm();
p.amethod();
}//End of main
public void amethod(){
int i=10;
System.out.println("Before another i= " +i);
another(i);
System.out.println("After another i= " + i);
}//End of amethod
public void another(int i){
i+=10;
System.out.println("In another i= " + i);
}//End of another
}

La salida será:

Before another i= 10
In another i= 20
After another i= 10

125
Tutorial para el examen de certificación: SCJP 1.2

Pregunta 1)
Dado el siguiente código:

class ValHold{
public int i = 10;
}
public class ObParm{
public static void main(String argv[]){
ObParm o = new ObParm();
o.amethod();
}
public void amethod(){
int i = 99;
ValHold v = new ValHold();
v.i=30;
another(v,i);
System.out.println(v.i);
}//End of amethod
public void another(ValHold v, int i){
i=0;
v.i = 20;
ValHold vh = new ValHold();
v = vh;
System.out.println(v.i+ " "+i);
}//End of another
}

¿Cual será la salida?

1)10,0, 30
2)20,0,30
3)20,99,30
4)10,0,20

Respuestas

Respuesta 1
4)10,0,20

126
javaHispano. Tu comunidad, tu lenguaje.

Otras Fuentes para este tema:


Tutorial de SUN:
http://java.sun.com/docs/books/tutorial/java/javaOO/arguments.html

Jyothi Krishnan cubre este tema en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec5.html#obj18

127
Tutorial para el examen de certificación: SCJP 1.2

Sección 6. Sobrecarga, sobreescritura, tipos en tiempo


de ejecución y orientación a objetos

Objetivo 1)

Mostrar los beneficios de la encapsulación en el diseño orientado a objetos y escribir


código que implemente clases fuertemente encapsuladas y entender las relaciones “es
un” y “tiene un”.

Relaciones “es un” y “tiene un”


Éste es un tema básico de OO y probablemente te encontrarás una pregunta sobre él en el
examen. Esencialmente busca descubrir si entiendes cuándo algo se refiere al tipo de
estructura de clases a la que pertenece un objeto y cuándo se refiere a un método o campo
que posee una clase.

Así, un gato ES UN tipo de animal y un gato TIENE UNA cola. Desde luego la
distinción puede ser difusa. Si fueras un zoólogo y conocieras los nombres correctos para
los grupos de tipos de animales podrías decir que un gato ES UN:

Largapalabraenlatínparagrupodeanimalesconcolas

Pero en lo que al examen se refiere esto no es un requisito.

Las preguntas del examen tienden a ser del tipo en las que se te da un texto que describe
una jerarquía potencial y te hace preguntas como: qué debería ser un campo y qué debería
ser un nuevo tipo de clase como hijo. A primera vista estas cuestiones pueden parecer
complejas, pero son bastante obvias si las lees con cuidado

Encapsulamiento

Los objetivos de Java 1.1 no mencionaban específicamente la encapsulación aunque sería


raro estudiar Java y no encontrarse con el concepto. La encapsulación conlleva a separar
la interfaz de una clase de su implementación. Esto significa que no se puede corromper
el valor de un campo “accidentalmente”, hay que usar un método para cambiar un valor.

La encapsulación conlleva esconder los datos de una clase y permitir el


acceso solo mediante una interfaz pública.

128
javaHispano. Tu comunidad, tu lenguaje.

Esto usualmente conlleva la creación de variables privadas (campos) cuyo valor se


actualiza y recupera mediante métodos. La convención estándar para dar nombre a estos
métodos es:
• SetNombreCampo
• GetNombreCampo

Por ejemplo, si cambiaras el color de una figura podrías crear un par de métodos de la siguiente
manera

public void setColor(Color c){


cBack = c;
}

public Color getColor(){


return cBack;
}
Las principales palabras claves para controlar el acceso a las variables son:
• public
• private
• protected
No te confundas pensando que el sistema de control de acceso tiene que ver con la seguridad.
Este no está diseñado para evitar que un programador acceda a variables, está diseñado para
ayudar a evitar modificaciones no deseadas.

El enfoque estándar al usar el ejemplo de arriba de color sería hacer privado el campo
CBack de Color. Un campo privado sólo es visible desde la clase en cuestión. Esto
significa que un programador no puede accidentalmente escribir código que cambie el
valor desde otra clase. Esto puede ayudar a reducir la introducción de errores.
La separación de la interfaz y la implementación hace más fácil modificar el código de
una clase sin afectar a otro código que lo pueda usar.
Para el diseñador de clases esto lleva a la posibilidad de modificar una clase, sabiendo
que no estropeará programas que la usen. Un diseñador de clases puede añadir rutinas de
comprobación adicionales para realizar “chequeos de cordura” relacionados con
modificaciones de campos. He trabajado en proyectos de seguros en los que era posible
que el cliente tuviera una edad menor de cero. Si un valor así se guarda en un campo
simple como un entero, no hay un lugar obvio en el que se puedan guardar rutinas de
comprobación. Si la edad es accesible sólo vía métodos set y get será posible insertar
comprobaciones de edades cero o negativas de forma que no quede afectado código
existente. Desde luego a medida que el desarrollo continúa se pueden descubrir más
situaciones que necesiten chequeo.
Para el usuario final de la clase esto significa que no tiene que comprender el
funcionamiento interno y que se le presenta una interfaz claramente definida para
manejar los datos. El usuario final puede tener la confianza de que las actualizaciones en
el código de la clase no romperán su código existente.

129
Tutorial para el examen de certificación: SCJP 1.2

Tipos en Tiempo de ejecución


Como el polimorfismo permite seleccionar en tiempo de ejecución la versión que se
ejecuta de un método, a veces no es obvio cuál será el método ejecutado. Véase el
siguiente ejemplo.
class Base {
int i=99;
public void amethod(){
System.out.println("Base.amethod()");
}
}
public class RType extends Base{
int i=-1;
public static void main(String argv[]){
Base b = new RType();//<= Nótese el tipo
System.out.println(b.i);
b.amethod();
}
public void amethod(){
System.out.println("RType.amethod()");
}

}
Nótese cómo el tipo de la referencia es la variable b es la clase Base pero el tipo de la
clase de hecho es RType. La llamada a amethod invocará la versión en RType pero la
salida b.i referenciará el campo i en la clase Base.

Pregunta 1)
Supón que te han entregado el siguiente diseño:
“Una persona tiene nombre, edad, dirección y sexo. Estás diseñando una clase para
representar un tipo de persona llamada paciente. Este tipo de persona puede recibir un
diagnóstico, tener cónyuge y está vivo". Dado que la clase persona ya ha sido creada, qué
de entre lo siguiente sería apropiado incluir cuando se diseñe la clase paciente?

130
javaHispano. Tu comunidad, tu lenguaje.

1)fecha de registro
2)edad
3)sexo
4)diagnóstico

Pregunta 2)
¿Qué sucederá cuando intentes compilar y ejecutar el siguiente código?
class Base {
int i=99;
public void amethod(){
System.out.println("Base.amethod()");
}
Base(){
amethod();
}
}
public class RType extends Base{
int i=-1;
public static void main(String argv[]){
Base b = new RType();
System.out.println(b.i);
b.amethod();
}
public void amethod(){
System.out.println("RType.amethod()");
}

1)
RType.amethod
-1
RType.amethod

2)
RType.amethod
99
RType.amethod

3)
99
RType.amethod

131
Tutorial para el examen de certificación: SCJP 1.2

4)
Error en tiempo de compilación

Pregunta 3)
Tu jefe diseñador de software te ha mostrado un esquema del nuevo sistema de partes de
ordenador que está a punto de crear. En lo alto de la jerarquía está una clase llamada
Ordenador y bajo ella hay dos clases hijas. Una se llama LinuxPC y la otra WindowsPC.
La principal diferencia entre las dos es que una ejecuta el Sistema Operativo Linux y la
otra ejecuta el sistema Windows (desde luego otra diferencia es que una necesita ser
rearrancada constantemente y la otra funciona fiablemente). Bajo WindowsPC hay dos
subclases, una llamada Server y la otra llamada Workstation. ¿Cómo valorarías el
trabajo de tu diseñador?

1)Dar la luz verde para posteriores diseños usando el esquema actual


2)Pedir un rediseño de la jerarquía cambiando el Sistema Operativo a un campo de la clase antes
que a un tipo de clase
3)Pedir que la opción WindowsPC se elimine ya que pronto quedará obsoleta
4) Cambiar la jerarquía para eliminar la necesidad de la superflua clase Ordenador.

Pregunta 4)
Dada la siguiente clase

class Base{
int Edad=33;
}

¿Cómo mejorarías la clase con respecto al acceso al campo Edad?


1)Definir la variable Edad como privada
2)Definir la variable Edad como protegida
3)Definir la variable Edad como privada y crear un método ‘get’ que la devuelva y un método
‘set’ que la actualice
4)Definir la variable Edad como protegida y crear un método ‘set’ que la devuelva y un
método ‘get’ que la actualice

Pregunta 5)
¿Cuáles de los siguientes son beneficios de la encapsulación?
1)Todas las variables pueden manipularse como objetos en vez de con primitivas
2)Haciendo todas las variables protegidas están protegidas de una corrupción accidental
3)Se puede cambiar la implementación de una clase sin estropear el código que la usa
4)Hacer todos los métodos protegidos previene la corrupción accidental de datos.

132
javaHispano. Tu comunidad, tu lenguaje.

Pregunta 6)
Nombre tres características principales de la Programación Orientada a Objetos:
1)Encapsulación, ligadura dinámica, polimorfismo
2)Polimorfismo, sobrecarga, redefinición
3)Encapsulación, herencia, ligadura dinámica
4)Encapsulación, herencia, polimorfismo

Pregunta 7)
¿Como implementas la encapsulación en una clase?
1)Haciendo todas las variables protegidas y sólo permitiendo el acceso vía métodos
2)Haciendo todas las variables privadas y sólo permitiendo el acceso vía métodos
3)Asegurando que todas las variables son representadas por clases envolventes
4)Asegurando que todas las variables son accedidas a través de métodos de una clase ancestra.

Respuestas

Respuesta 1)
1) fecha de registro
4) diagnóstico

La fecha de registro es razonable como campo adicional para un paciente, y el diseño


específicamente dice que un paciente debería tener un diagnóstico. Como el paciente es
un tipo de persona, debería tener disponibles los campos edad y sexo (asumiendo que no
fueran declarados como privados).

Respuesta 2)
2)
RType.amethod
99
RType.amethod

Si esta respuesta te parece improbable, intenta compilar y ejecutar el código. La razón es


que este código crea una instancia de la clase Rtype pero la asigna a una referencia a la
clase Base. En esta situación una referencia a cualquiera de los campos como es el caso
de ‘i’se referirá al valor en la clase Base, pero una llamada a un método hará referencia
al método en la clase Rtype antes que a su manejador de referencia.

Respuesta 3)
2) Pedir un rediseño de la jerarquía cambiando el Sistema Operativo a un campo de la
clase antes que a un tipo de clase
Respuesta 4)

133
Tutorial para el examen de certificación: SCJP 1.2

3) Definir la variable Edad como privada y crear un método get que la devuelva y un
método set que la actualice.

Respuesta 5)
3) Se puede cambiar la implementación de una clase sin estropear el código que la usa.

Respuesta 6)
4) encapsulación, herencia, polimorfismo
Me hicieron esta pregunta en una entrevista de trabajo una vez. Conseguí el trabajo. No
puedes tener la seguridad de encontrar algo así en el examen, pero bien viene saberlo.

Respuesta 7)
2)Haciendo todas las variables privadas y sólo permitiendo el acceso vía métodos

Otras Fuentes para este tema:


Este tema se cubre en el Tutorial de Sun en:
http://java.sun.com/docs/books/tutorial/java/concepts/index.html

Richard Baldwin cubre este tema en:


http://www.Geocities.com/Athens/Acropolis/3797/Java004.htm#an initial description of
oop
(Esto es material general sobre OOP más que sobre "es un" / "tiene un")

Jyothi Krishnan sobre este tema en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec6.html#obj19

Java 1.1 Unleashed


http://www.itlibrary.com/reference/library/1575212986/htm/ch05.htm
(Ver la sección sobre encapsulación)
http://www.geocities.com/SiliconValley/Network/3693/obj_sec6.html - obj19

134
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 2)

Escribir código para invocar métodos sobrecargados y sobrescritos; constructores


paternos o sobrecargados y describir el efecto de invocar estos métodos.

Comentario sobre el objetivo


Los términos overloaded (sobrecargado) y overriden (sobrescrito, redefinido o
sobrepasado) son en inglés lo bastante similares como para llevar a la confusión. Mi
forma de recordarlo es imaginar que algo que ha sido redefinido o sobrepasado es algo a
lo que le ha pasado encima un vehículo pesado y ya no existe por sí mismo. Algo que ha
sido sobrecargado todavía se mueve pero está cargado con montones de funcionalidades
que le causan un gran esfuerzo. Esto es sólo un pequeño truco para distinguir a ambos, no
tiene ninguna relación con la realidad del funcionamiento de Java.

Sobrecarga de métodos
La sobrecarga de métodos es un truco del compilador para permitirte usar el mismo
nombre para realizar acciones distintas dependiendo de los parámetros.

Entonces, imagina que estás diseñando la interfaz para un sistema que haga exámenes de
certificación de Java falsos (¿quién podría saber?). Una respuesta podría venir como un
entero, un booleano o una cadena de texto. Podrías crear una versión del método para
cada tipo de parámetro y darle el nombre correspondiente como:

marcarespuestaboolean(boolean respuesta){
}

marcarespuestaint(int respuesta){
}

marcarespuestaString(String respuesta){
}

Esto funcionaría pero supone que los futuros usuarios de tus clases tendrán que saber más
nombres de métodos de lo estrictamente necesario. Sería más útil si pudieras usar un solo
nombre de método y el compilador resolviera a qué código llamar según el tipo y el
número de parámetros de la llamada.

Este es el núcleo de la sobrecarga de métodos, parte de lo cual se conoce como


polimorfismo.

No hay palabras claves que recordar para sobrecargar métodos, sólo se crean múltiples
métodos con el mismo nombre pero distinto número y/o tipo de parámetros. Los nombres

135
Tutorial para el examen de certificación: SCJP 1.2

de los parámetros no son importantes pero el número y los tipos sí deben ser diferentes.
Así, el siguiente es un ejemplo de un método marcarespuesta sobrecargado

void marcarespuesta(String respuesta){


}

void marcarespuesta(int respuesta){


}

El siguiente no es un ejemplo de sobrecarga y causará un error en tiempo de compilación


indicando una declaración duplicada de método.

void marcarespuesta(String respuesta){


}

void marcarespuesta(String titulo){


}

El tipo de retorno no forma parte de la identificación en cuanto a la sobrecarga.

Por tanto, cambiárselo a uno de los métodos de arriba por int aún producirá un error en
tiempo de compilación, pero esta vez indicando que no se puede redefinir un método con
un tipo de retorno distinto.

Los métodos sobrecargados no tienen restricciones en cuanto a qué excepciones se


pueden hacer lanzar (hacer throw). Esto sí es algo a tener en cuenta con la redefinición.

Los métodos se diferencian sólo en el número, tipo y orden de los


parámetros, no en el tipo de retorno del método

Sobrescritura de métodos

Sobrescribir un método significa que se reemplaza su funcionalidad entera. Se hace en


una clase hija con un método definido en una clase padre. Para redefinir un método se
define uno nuevo en la clase hija con exactamente la misma identificación que el de la
clase padre. Esto tiene el efecto de obscurecer el método en la clase padre y de que la
funcionalidad de éste ya no sea directamente accesible.

Java proporciona un ejemplo de redefinición en el caso del método equals que cada
clase hereda de la gran clase antecesora Object. La versión heredada de equals

136
javaHispano. Tu comunidad, tu lenguaje.

simplemente compara a qué lugar de la memoria referencia la instancia de la clase. A


menudo esto no es lo que se desea, particularmente en el caso de un String. Para una
cadena generalmente querrías una comparación carácter a carácter para ver si las dos
cadenas son la misma. Para permitir esto la versión de equals que viene con String es
una versión redefinida que efectúa esta comparación carácter a carácter.

Invocando constructores de clases base

Un constructor es un método especial que se ejecuta automáticamente cada vez que se


crea una instancia de una clase. Java sabe que un método es un constructor porque tiene
el mismo nombre que la clase misma y no tiene valor de retorno. Un constructor puede
recibir parámetros como cualquier otro método y puedes necesitar diferentes parámetros
según cómo quieras que la clase se inicialice. Así si te fijas en el ejemplo en la clase
Button del paquete AWT su constructor está sobrecargado para que tenga dos versiones.

• Button()
• Button(String label)

Así, puedes crear un botón sin etiqueta y dársela después, o usar la opción más común y
asignarle la etiqueta en el momento de la creación.

Sin embargo, los constructores no se heredan, así que si quieres sacar un constructor útil
de una clase ancestro no está disponible por defecto. Así, el siguiente código no
compilará

class Base{
public Base(){}
public Base(int i){}
}

public class MiRedef extends Base{


public static void main(String argvp[]){
MiRedef m = new MiRedef(10);// NO compilará
}

La palabra mágica que necesitas para acceder a un constructor de un ancestro es super.


Esta palabra clave se puede usar como si fuera un método y recibir parámetros que
concuerden con la versión deseada del constructor padre. En este ejemplo modificado del
código previo se usa la palabra clave super para llamar a la versión con el entero del
constructor en la clase base y el código se compila sin problemas.

137
Tutorial para el examen de certificación: SCJP 1.2

class Base{
public Base(){}
public Base(int i){}
}
public class MiRedef extends Base{
public static void main(String arg[]){
MiRedef m = new MiRedef(10);
}
MiRedef(int i){
super(i);
}

Invocando constructores con this()

De la misma forma que se puede llamar al constructor de una clase base usando super()
se puede llamar a otro constructor de la clase en cuestión usando this como si fuera un
método. Así en el ejemplo anterior se podría definir otro constructor de la siguiente
manera

MiRedef(String s, int i){


this(i);
}

Tanto this como super se pueden llamar en la primera línea desde un


constructor, pero no ambos a la vez.

Como habrás adivinado esto llamará al otro constructor de la clase actual que toma un
solo entero como parámetro. Si usas super() o this() en un constructor debe ser la
primera llamada a un método. Como sólo uno de los dos puede ser el primer método
llamado, no puedes usar a la vez super() y this() en un constructor.

Así, lo siguiente causará un error en tiempo de compilación.

MiRedef (String s, int i){


this(i);
super();// Causa un error en tiempo de compilación.
}

138
javaHispano. Tu comunidad, tu lenguaje.

Basándonos en el conocimiento de que los constructores no se heredan, debe resultar


obvio que la redefinición es irrelevante. Si tienes una clase llamada Base y creas una
clase hija que la extiende, para la clase que la extiende redefinir el constructor debe tener
el mismo nombre. Esto causaría un error en tiempo de compilación. Aquí hay un ejemplo
de esta jerarquía absurda.

class Base{}
class Base extends Base{} // ¡Error en tiempo de compilación!

El constructor y la jerarquía de clases

Los constructores siempre se llaman hacia abajo desde lo alto de la jerarquía. Es muy
probable que en el examen te hagan preguntas relativas a una jerarquía de clases con
varias llamadas a this y super y tengas que elegir cuál será el resultado. Ten cuidado
con las preguntas en las que tienes una jerarquía compleja que resulta irrelevante a causa
de un constructor que hace una llamada tanto a this como a super y por tanto se
produce un error en tiempo de compilación.

Los constructores se llaman desde la base (ancestro) de la jerarquía


hacia abajo

Sea el siguiente ejemplo:

class Mamífero{
Mamífero (){
System.out.println("Creando Mamífero ");
}
}

public class Humano extends Mamífero {


public static void main(String argv[]){
Humano h = new Humano();
}
Humano(){
System.out.println("Creando Humano");
}
}

139
Tutorial para el examen de certificación: SCJP 1.2

Cuando se ejecute este código la cadena “Creando Mamífero” aparece primero debido a
la llamada implícita al constructor sin argumentos de la base de la jerarquía.

Pregunta 1)

Dada la siguiente definición de clase, ¿cuál de los siguientes métodos podría colocarse
legalmente después del comentario con la palabra comentada “//Aquí”?

public class Rid{


public void amethod(int i, String s){}
//Aquí
}

1) public void amethod(String s, int i){}


2) public int amethod(int i, String s){}
3) public void amethod(int i, String mystring){}
4) public void Amethod(int i, String s) {}

Pregunta 2)

Dada la siguiente definición de clase, ¿cuál de los siguientes métodos podría colocarse
legalmente después del comentario con la palabra comentada “//Aquí”?

140
javaHispano. Tu comunidad, tu lenguaje.

public class MyOver extends Base{


public static void main(String arg[]){
MyOver m = new MyOver(10);
}
MyOver(int i){
super(i);
}
MyOver(String s, int i){
this(i);
//Aquí

}
}

1) MyOver m = new MyOver();


2) super();
3) this("Hola",10);
4) Base b = new Base(10);

Pregunta 3)

Dada la siguiente definición de clases:

class Mamífero{
Mamífero (){
System.out.println("Mamífero ");
}
}
class Perro extends Mamífero {
Perro(){
System.out.println("Perro");
}
}

public class Collie extends Perro {


public static void main(String argv[]){
Collie c = new Collie();
}
Collie(){
this("Buen Perro");
System.out.println("Collie");

141
Tutorial para el examen de certificación: SCJP 1.2

}
Collie(String s){
System.out.println(s);
}

¿Cuál será la salida?

1)Error al compilar
2)Mamífero, Perro, Buen Perro, Collie
3)Buen Perro, Collie, Perro, Mamífero
4)Buen Perro Collie

Pregunta 4)

¿Cuáles de las siguientes sentencias son verdaderas?

1)Los constructores no se pueden heredar


2)Un constructor se puede sobrescribir
3)Un constructor padre se puede invocar utilizando this
4)Cualquier método puede contener una llamada a this o super

Pregunta 5)

¿Qué pasara cuando intentes compilar y ejecutar el siguiente código?

class Base{
public void amethod(int i, String s){
System.out.println("Base amethod");
}
Base(){
System.out.println("Base Constructor");
}

public class Child extends Base{


int i;
String Parm="Hello";
public static void main(String argv[]){
Child c = new Child();
c.amethod();
}

void amethod(int i, String Parm){

142
javaHispano. Tu comunidad, tu lenguaje.

super.amethod(i,Parm);
}
public void amethod(){}
}

1)Error al compilar
2)Error causado por la sintaxis ilegal en: super.amethod(i,Parm);
3)Mostrará “Base Constructor”
4)Error causado por los nombres incorrectos de los parámetros en la llamada a;
super.amethod

Pregunta 6)

¿Cuál será la salida del siguiente código si intentas compilarlo y ejecutarlo?

class Mammal{
Mammal(){
System.out.println("Four");
}
public void ears(){
System.out.println("Two");
}
}
class Dog extends Mammal{
Dog(){
super.ears();
System.out.println("Three");
}
}

public class Scottie extends Dog{


public static void main(String argv[]){
System.out.println("One");
Scottie h = new Scottie();
}
}

1) One, Three, Two, Four


2) One, Four, Three, Two
3) One, Four, Two, Three
4) Error al compilar

Respuestas

Respuesta 1)

143
Tutorial para el examen de certificación: SCJP 1.2

1) public void amethod(String s, int i){}


4) public void Amethod(int i, String s) {}

La letra A mayúscula en Amethod nos indica que es un método distinto a amethod

Respuesta 2)

4) Base b = new Base(10);

Cualquier llamada a this o super debe estar en la primera línea del constructor. Como
en el método ya se utilizó this, ninguna otra opción puede ser utilizada

Respuesta 3)

2) Mamífero, Perro, Buen Perro, Collie

Respuesta 4)

1)Los constructores no se pueden heredar

Los constructores padres con invocados utilizando this o super

Repuesta 5)

1)Error al compilar

Esto causa un error que indica algo como lo siguiente: “no puedes sobrescribir métodos
para hacerlos privados”, amethod en la clase Base esta definido como privado, y en
Child al no ponerle modificador de acceso antes de void, estas intentando alterar el
modificador public.

Respuesta 6)

3) One, Four, Two, Three

Las clases son creadas desde la raíz del la jerarquía de herencia hacia abajo.

144
javaHispano. Tu comunidad, tu lenguaje.

Otras Fuentes para este tema:


Este tema es cubierto el Tutorial de SUN en:
http://java.sun.com/docs/books/tutorial/java/javaOO/methoddecl.html

Richard Baldwin cubre este tema en:


http://www.Geocities.com/Athens/Acropolis/3797/Java004.htm#polymorphism in
general
(Material sobre POO concerniente a "es un" y “tiene un")

Jyothi Krishnan en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec6.html#obj20

145
Tutorial para el examen de certificación: SCJP 1.2

Objetivo 3)

Escribir código que construya instancias de una clase en concreto, incluyendo clases de
nivel superior, clases internas, clases internas estáticas y clases anónimas.

Nota sobre este objetivo

Parte de este material es cubierto en la sección 4.

Instanciando una clase

Concretamente, las clases pueden ser instanciadas como una referencia a un objeto
(también llamada simplemente objeto). De esta manera, una clase abstracta no puede ser
instanciada y por lo tanto no se puede crear una referencia a un objeto. Recuerda que una
clase que contiene un método abstracto es abstracta por si misma y no puede ser
instanciada.

La manera para instanciar una clase es usando la palabra clave new. Típicamente se
utiliza de la siguiente manera:

Button b = new Button();

La sintaxis indica que la variable name es del tipo Button y contiene una referencia a
una instancia de Button. Sin embargo aunque el tipo de la referencia es frecuentemente
el mismo que el tipo de la clase instanciada, esto no necesariamente tiene que se así. El
siguiente código es valido:

Object b = new Button();

La sintaxis anterior indica que el tipo de la referencia de b es Object en lugar de


Button.

La declaración e instanciación puede no ocurrir en la misma línea, Así, puedes construir una
instancia de una clase de la siguiente manera:

Button b;
b=new Button();

Clases internas

146
javaHispano. Tu comunidad, tu lenguaje.

Las clases internas fueron introducidas con la liberación del JDK 1.1. Las clases internas
permiten definir clases dentro de otras clases, en ocasiones estas clases son conocidas
como clases anidadas. Son usadas extensivamente a partir del modelo de eventos de JDK
1.1. Con certeza encontraras en el examen preguntas acerca de las clases anidadas y del
alcance de ellas.

Este es un ejemplo sencillo:

class Nest {
class NestIn{}
}

La salida cuando este código se compile serán dos archivos .class. El primero, que es el
que esperas es:

Nest.class

el otro es

Nest$NestIn.class

Esto ilustra que el anidamiento de clases es generalmente una convención para nombrar
clases en lugar de una nueva clasificación de archivos .class. Las clases internas te
permite hacer una agrupación lógica de clases. También tienen beneficios para controlar
el alcance de las variables.

Clases Anidadas de nivel Superior (Top Level)

Una clase anidada de nivel superior es un miembro estático contenido dentro de una clase
de nivel superior.

class Nest{
static class NestIn{}
}

Este tipo de anidamiento es usado frecuentemente para agrupar de una manera sencilla
clases que guardan una relación entre si. Debido a que la clase es estática no requiere una
instancia de la clase externa para existir.

Clases Miembro

Veo una clase miembro como una “clase interna ordinaria”. Una clase miembro es
semejante a otros miembros de una clase, debes instanciar la clase exterior antes de crear
una instancia de la clase interna. Debido a la necesidad que tiene la clase interna de ser
asociada con una instancia de la clase externa, Sun introduce una nueva sintaxis para

147
Tutorial para el examen de certificación: SCJP 1.2

permitir la creación simultánea de una instancia de la clase externa y al mismo tiempo la


creación de la clase interna. Es de esta forma:

Outer.Inner i = new Outer().new Inner();

Para darle sentido a esta nueva sintaxis, intenta pensar que la primera aparición de la
palabra clave new es usada en el ejemplo anterior para designar la pertenencia a la
instancia actual this.

Así, podrías cambiar la línea que crea la instancia de ésta clase y leer lo siguiente:

Inner i = this.new Inner();

Debido a que una clase miembro no puede existir sin un instancia de la clase exterior,
ésta puede tener acceso a las variables de la clase exterior.

Clases creadas dentro de métodos

Un nombre más correcto para este tipo de clases es clase local.

Las clases locales solo pueden acceder a campos finales o parámetros


del método que la contiene

Una clase local es visible únicamente dentro del bloque de código del método. El código
dentro de la clase local puede usar únicamente variables locales que tengan el
modificador final en el bloque del método o parámetros del método. Es muy probable
que te encuentres con preguntas de este tipo en el examen.

Clases anónimas

Tu primera reacción con la idea de una clase anónima debe ser "¿por qué querría yo tener
una clase sin nombre? y ¿cómo podría referirme a una clase si no tiene nombre?"

Para contestar estas preguntas, considera lo siguiente. Podrías estar en una situación en
donde constantemente tienes que pensar en nombres para instancias de clases en donde el
nombre es por si mismo evidente. Por ejemplo en el manejo de eventos las dos cosas mas
importantes que necesitas saber para manejar el evento son: el evento que se va a manejar
y el nombre del componente que esta utilizando dicho manejador. Tener el nombre de la
instancia la clase que maneja el evento no aporta mucho valor.

148
javaHispano. Tu comunidad, tu lenguaje.

Acerca de la pregunta de como puedes hacerle referencia, pues, simplemente no puedes y


si necesitas referirte a la clase por su nombre, entonces no deberías crear una clase
anónima. La falta del nombre de la clase tiene efectos adicionales, como el hecho de que
no puedes darle a la clase anónima un constructor.

Las clases anónimas no pueden tener constructores

Este es un ejemplo de una clase interna anónima:

class Nest{
public static void main(String argv[]){
Nest n = new Nest();
n.mymethod(new anon(){});
}
public void mymethod(anon i){}
}
class anon{}

Nota que la declaración y definición de la clase anónima se realiza dentro de los


paréntesis de la llamada a mymethod.

Pregunta 1)

¿Cuáles de las siguientes afirmaciones son verdaderas?

1)Una clase definida dentro de un método puede únicamente acceder métodos estáticos
del método que la contiene
2)Una clase definida dentro de un método puede únicamente acceder variables finales del
método que la contiene
3)Una clase definida dentro de un método no puede acceder a algún campo del método
que la contiene

149
Tutorial para el examen de certificación: SCJP 1.2

4)Una clase definida dentro de un método puede acceder cualquier campo accesible del
método que la contiene

Pregunta 2)

¿Cuáles de las siguientes afirmaciones son verdaderas?

1)Una clase anónima no puede tener un constructor


2)Una clase anónima puede ser creada únicamente dentro del cuerpo de un método
3)Una clase anónima puede únicamente acceder a campos estáticos del método que la
contiene
4)El tipo de clase de una clase anónima puede ser obtenido utilizando el método
getName

Pregunta 3)

¿Cuáles de las siguientes afirmaciones son verdaderas?

1)Una clase interna no puede ser marcada como privada


2) Una instancia de una clase anidada de nivel superior puede crearse sin necesidad de
crear una instancia de la clase que la contiene
3)Un archivo que contenga una clase externa y una interna únicamente producirá un
único archivo .class
4) Para crear una instancia de una clase miembro se requiere crear una instancia de la
clase que la contiene

Respuestas

Respuesta 1)
2)Una clase definida dentro de un método puede únicamente acceder variables finales del
método que la contiene

Respuesta 2)
1)Una clase anónima no puede tener un constructor

Respuesta 3)

2) Una instancia de una clase anidada de nivel superior puede crearse sin necesidad de
crear una instancia de la clase que la contiene
4) Para crear una instancia de una clase miembro se requiere crear una instancia de la
clase que la contiene

150
javaHispano. Tu comunidad, tu lenguaje.

Una clase anidada genera por si misma un archivo .class, usando el formato:

Outer$Inner.class

Una clase anidada de nivel superior es como una clase estática así que no requiere una
instancia de la clase que la contiene. Una clase miembro es como una clase no estática,
por consiguiente se requiere una instancia de la clase que la contiene,.

Otras Fuentes para este tema:


Tutorial de Sun:
http://java.sun.com/docs/books/tutorial/java/more/nested.html

Richard Baldwin
http://www.geocities.com/Athens/7077/Java094.htm

Jyothi Krishnan en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec6.html#obj21

151
Tutorial para el examen de certificación: SCJP 1.2

Sección 7. Threads

Objetivo 1)
Escribir código para definir, instanciar y comenzar nuevos threads usando
java.lang.Thread y java.lang.Runnable.

¿Qué es un Thread ?

Los Threads son procesos ligeros que aparentan correr en paralelo con tu programa
principal. A diferencia de los procesos un thread comparte memoria y datos con el resto
del programa. La Palabra Thread es una contracción de “Thread de ejecución” (Hilo de
ejecución), puedes imaginar una cuerda, a la cual le has deshilachado el final y has
tomado un hilo. El hilo todavía es parte de la misma cuerda, pero puede ser separado de
la principal y ser manipulado por si solo. Un ejemplo de donde pueden ser útiles los
threads, es en la impresión. Cuando das un click en el botón imprimir, probablemente no
quieras que el programa principal se detenga hasta que finalice la impresión. Lo deseable,
seria que el proceso de impresión comenzara a ejecutarse en segundo plano y te
permitiera continuar usando la parte principal del programa.

También sería útil si el programa principal pudiera responder si el hilo (thread) de


impresión encontrara algún problema. Un ejemplo común utilizado para ilustrar los
threads es el crear una aplicación GUI que lanzara una pelota rebotando cada vez que un
botón es presionado. A diferencia de otros lenguajes el threading esta embebido en el
corazón de Java, mucho de él al nivel de la ultima clase ancestro llamada Object.

Las dos formas de crear un Hilo (Thread)

De las dos maneras de crear un Hilo (algunos documentos ocupan la palabra hebra en
lugar de hilo) el uso de Runnable es probablemente el mas común, pero debes de
conocer las dos para propósitos del examen. El siguiente es un ejemplo de una clase
creada con la interface Runnable.

class MyClass implements Runnable {


public void run() {
//Blank Body
}
}

Creando el hilo de ejecución.

MyClass mc = new MyClass();

152
javaHispano. Tu comunidad, tu lenguaje.

Cualquier clase que implemente una interfase debe crear un método correspondiente por
cada uno de los que se encuentren en la interfase. No es necesario que los métodos
realicen algo, pueden tener el cuerpo del método en blanco, pero deben estar ahí. De esta
manera incluí el método run incluso en este pequeño ejemplo, ya que si implementas
Runnable debes incluir el método run No incluir el método run causaría un error en
tiempo de compilación.

Para hacer algo útil cuando se crea un hilo de ejecución de una clase deberías de, por
supuesto, colocar algo de código donde puse :

//Blank body

La otra manera de crear un hilo es crear una clase que descienda de Thread. Esto es fácil
de hacer pero significa que no puedes heredar de ninguna otra clase, debido a que Java
solo soporta herencia simple. De esta manera, si estas creando un botón no le puedes
agregar threading a de esta manera porque un botón hereda de la clase AWT Button y
eso utiliza tu única opción de herencia. Existe debate sobre cual de las dos formas de
crear un hilo es verdaderamente más orientada a objetos, pero no necesitas llegar a esa
conclusión para propósitos del examen.

Instanciando e Iniciando un hilo.

Aunque el código que se ejecuta en tu thread esta en un método llamado run, no


necesitas llamar a este método directamente, en vez de eso llamas al método start de la
clase Thread. La interfase Runnable no contiene un método start, entonces, para
llegar a este método y a los otros útiles métodos para threads (sleep, suspend, etc),
pasas tu clase con la interfase Runnable como el constructor de una instancia de la clase
Thread.

De este modo para hacer que el hilo se ejecute desde una clase que implemente
Runnable deberás llamar lo siguiente:

MyClass mc = new MyClass();


Thread t = new Thread(mc);
t.start();

De nuevo observa que fue una llamada al método start, no una llamada al método run,
aunque es el código en el método run en tu clase el que actualmente se ejecuta.

Aunque es el método run el que ejecuta, un hilo se inicia a través


del método start.

153
Tutorial para el examen de certificación: SCJP 1.2

Si creas una clase que sea una subclase de Thread simplemente


tienes que llamar al método start. El inconveniente de heredar de
la clase Thread, es que debido al soporte de herencia simple no
puedes heredar funcionalidad de ninguna otra clase.

Preguntas

Pregunta 1)
¿Qué ocurrirá cuando intentes compilar y ejecutar el siguiente código?

public class Runt implements Runnable{


public static void main(String argv[]){
Runt r = new Runt();
Thread t = new Thread(r);
t.start();
}

public void start(){


for(int i=0;i<100;i++)
System.out.println(i);
}
}

1)Compila y tiene como salida una cuenta de 1 a 99


2)Compila pero no tiene salida
3)Error en tiempo de compilación: La clase Runt es una clase abstracta. No puede ser
instanciada
4)Error en tiempo de compilación, el método start no puede ser llamado directamente

Pregunta 2)
¿Cuáles de las siguientes frases es cierta?

1)Heredar directamente de la clase Thread te da acceso a más funcionalidad de las


capacidades de tareas de Java que implementar la interfase Runnable
2)Usar la interfase Runnable significa que no tienes que crear una instancia de la clase
Thread y llamar al método run directamente.

154
javaHispano. Tu comunidad, tu lenguaje.

3)Utilizando ambas, La interfase Runnable y heredar de la clase Thread requiere el


llamado al método start para comenzar la ejecución
4)La interfase Runnable requiere únicamente implementar un método, que es llamado
run

Pregunta 3)
¿Qué ocurrirá cuando intentes compilar y ejecutar el siguiente código?

public class Runt extends Thread{


public static void main(String argv[]){
Runt r = new Runt();
r.run();
}

public void run(){


for(int i=0;i<100;i++)
System.out.println(i);
}
}

1)Compila y tiene como salida una cuenta de 1 a 99


2)Compila pero no tiene salida
3)Error en tiempo de compilación: La clase Runt es una clase abstracta. No puede ser
instanciada
4)Error en tiempo de compilación, el método start no ha sido definido

Pregunta 4)
¿Cuáles de las siguientes frases es cierta?

1)Para implementar el Threading en un programa debes importar la clase


java.io.Thread
2)El código que se ejecuta cuando inicias un hilo es colocado en el método run
3)Los Threads pueden compartir datos entre unos y otros
4)Para comenzar la ejecución de un Thread, llamas al método start y no al método
run.

Respuestas

Respuesta 1)

3) Error en tiempo de compilación: La clase Runt es una clase abstracta. No puede ser
instanciada

155
Tutorial para el examen de certificación: SCJP 1.2

La clase implementa Runnable pero no define el método run.

Respuesta 2)

3) Usar la interfase Runnable significa que no tienes que crear una instancia de la clase
Thread y llamar al método run directamente.
4) La interfase Runnable requiere únicamente implementar un método, que es llamado
run

Respuesta 3)
1)Compila y tiene como salida una cuenta de 1 a 99

Sin embargo, observa que este código no inicia la ejecución del hilo y el método run no
debe ser llamado de esta forma.

Respuesta 4)

2)El código que se ejecuta cuando inicias un hilo es colocado en el método run
3)Los Threads pueden compartir datos entre unos y otros
4)Para comenzar la ejecución de un Thread, llamas al método start y no al método
run.

No necesitas importar ninguna clase ya que el Threading es una parte integral de Java.

Otras Fuentes sobre este tema

Este tema esta cubierto en el tutorial de sun en


http://java.sun.com/docs/books/tutorial/essential/threads/customizing.html

Richard Baldwin cubre este tema en


http://www.Geocities.com/Athens/Acropolis/3797/Java058.htm#two ways to thread

Jyothi Krishnan sobre este tema en


http://www.geocities.com/SiliconValley/Network/3693/obj_sec7.html#obj22

La parte de Threads del Tutorial de Elliot Rusty Harold


http://www.ibiblio.org/javafaq/course/week11/index.html

156
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 2)

Reconocer las condiciones que puedan impedir que un Thread se ejecute

Comentario de este objetivo

La expresión “impedir que un thread se ejecute” es ligeramente ambigua, ¿significa que


un hilo ha sido pausado deliberadamente, o también incluye hilos que han muerto?. Se
dice que un hilo a sido bloqueado cuando se le ha impedido ejecutarse.

Razones por las que un thread puede ser bloqueado

Un hilo puede ser bloqueado por que:

Ha sido puesto a dormir por una cantidad de tiempo


• Ha sido suspendido por una llamada al método suspend() y estará bloqueado
hasta una llamada al método resume()
• El hilo ha sido suspendido por una llamada al método wait(), y se volverá
ejecutable con un mensaje notify o notifyAll.

Para propósitos del examen sleep(), y wait/notify son probablemente las más
importantes de las situaciones por las que un hilo pueda ser bloqueado.

El método sleep es estático y detiene la ejecución de un hilo por un número fijo de


milisegundos. Existe una versión que supuestamente debe pausar por un número fijo de
nanosegundos, aunque encuentro difícil de creer que alguien pueda trabajar en una
máquina o implementación de Java que trabaje a ese nivel de precisión. El siguiente es un
ejemplo para poner a dormir un hilo, nota como el método sleep lanza
InterruptedException. El hilo:

public class TSleep extends Thread{


public static void main(String argv[]){
TSleep t = new TSleep();
t.start();
}
public void run(){
try{
while(true){
this.sleep(1000);
System.out.println("looping while");
}
}catch(InterruptedException ie){}
}
}

157
Tutorial para el examen de certificación: SCJP 1.2

Con la salida de Java 2, los métodos de la clase Thread : stop, suspend y resume han
quedado obsoletos (depracated, no se recomienda que se usen y al utilizarlos se envía una
advertencia en tiempo de compilación). Las notas del JDK indican lo siguiente:

//Quote
Obsoleto. Este método ha sido censurado, ya que es inherentemente propenso a crear deadlocks.
Si el hilo objetivo mantiene un bloqueo sobre el monitor protegiendo un recurso de sistema
crítico cuando queda suspendido, ningún otro hilo puede acceder a este recurso hasta que el hilo
objetivo es reiniciado. Si el Hilo que intenta resumir al hilo objetivo intenta realizar un bloqueo
antes de llamar a resume(), ocurre un deadlock. Tales deadlocks típicamente se manifiestan como
procesos “congelados”. Para mas información vea ¿Por que son Obsoletos los métodos:
Thread.stop, Thread.suspend y Thread.resumen?
//End Quote

Una fuente generalmente confiable (Kathy Kozel) ha indicado que tienes que estar
conciente de esto para propósitos del examen. Yo asumiré que actualmente no necesitas
conocer como usarlos.

El bloqueo del Thread vía el protocolo wait/notify es cubierto en el siguiente tema

Pregunta 1)
¿Qué ocurrirá cuando intentes compilar y ejecutar el siguiente código?

public class TGo implements Runnable{


public static void main(String argv[]){
TGo tg = new TGo();
Thread t = new Thread(tg);
t.start();
}
public void run(){
while(true){
Thread.currentThread().sleep(1000);
System.out.println("looping while");
}
}
}

1)Compila y no tiene salida

158
javaHispano. Tu comunidad, tu lenguaje.

2)Compila y tiene como salida el texto “looping while” repetidamente


3)Compila y tiene como salida el texto “looping while” una sola vez
4)Error en tiempo de compilación

Pregunta 2)

¿Cuál de las siguientes formas es una manera recomendada para que un Thread pueda
ser bloqueado?

1)sleep()
2)wait/notify
3)suspend
4)pause

Pregunta 3)
¿Cuáles de las siguientes frases son verdaderas?

1)El método sleep toma parámetros del Hilo y el número de segundos que debe dormir
2)El método sleep toma un solo parámetro que indica el número de segundos que debe
dormir
3)El método sleep toma un solo parámetro que indica el número de milisegundos que
debe dormir
4)El método sleep es un método estático de la clase Thread

Respuestas

Respuesta 1)

4 )Error en tiempo de compilación

El método sleep lanza InterruptedException y de esta manera este código no


compilara hasta que el ciclo while quede envuelto en un bloque try/catch

Respuesta 2)

1)sleep()
2)wait/notify

Para la plataforma Java 2 el método suspend ha sido censurado y de esta manera es


válido pero no recomendado.

Respuesta 3)

159
Tutorial para el examen de certificación: SCJP 1.2

3)El método sleep toma un solo parámetro que indica el número de milisegundos que
debe dormir
4)El método sleep es un método estático de la clase Thread

Otras Fuentes sobre este tema

Este tema esta cubierto en el tutorial de sun en


http://java.sun.com/docs/books/tutorial/essential/threads/waitAndNotify.html

Richard Baldwin cubre este tema en


http://www.geocities.com/Athens/Acropolis/3797/Java058.htm#the notify() and wait()
methods

Jyothi Krishnan sobre este tema en


http://www.geocities.com/SiliconValley/Network/3693/obj_sec7.html#obj23

Comentario de métodos deprecados en


http://java.sun.com/docs/books/tutorial/post1.0/preview/threads.html

160
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 3)

Escribir código utilizando: synchronized, wait, notify, y notifyAll, para


proteger el código contra los problemas de acceso concurrente y la comunicación entre
los hilos. Definir la interacción de bloqueos entre hilos y entre hilos y objetos cuando
ejecutan los métodos: synchronized, wait, notify, y notifyAll.

¿Por qué necesitarías el protocolo wait/notify?

Una manera de pensar en una utilidad para el protocolo wait/notify es imaginar un


dato, por ejemplo una variable entera, e imaginar que es un campo en una base de datos.
Si no tienes algún mecanismo de bloqueo en la base de datos existe la posibilidad de
corromper los datos.

Así un usuario podría obtener los datos, realizar un cálculo y escribir los datos. Si en el
entretanto alguien más ha recuperado los datos, ha realizado un cálculo y lo ha escrito,
los segundos cálculos de los usuarios se perderán cuando la primera persona escriba en la
base de datos.

synchronized

La palabra clave synchronized se utiliza para marcar una sentencia o bloque de código
e indicar que únicamente un hilo a la vez puede ejecutar una instancia del código. La
entrada al código esta protegida por un supervisor o monitor de bloqueos. Este proceso es
implementado por un sistema de bloqueos. Se asigna un bloqueo al objeto y así se
asegura que únicamente un hilo a la vez pueda acceder al código. Así cuando un hilo
empieza a ejecutar un bloque sincronizado este adopta el bloqueo. Cualquier otro hilo no
podrá ejecutar el código hasta que el primer hilo haya finalizado y liberado el bloqueo.
Nota que el bloqueo esta basado en el objeto y no en el método.

Para un método la palabra clave synchronized se coloca antes de la definición del


método:

synchronized void amethod() { /* method body */}

Para un bloque de código la palabra va antes de la apertura y cerradura de llaves.

synchronized (ObjectReference) { /* Block body */ }

El valor entre paréntesis indica el objeto o clase que necesita obtener el supervisor. Es
generalmente más común sincronizar un método que un bloque de código.

161
Tutorial para el examen de certificación: SCJP 1.2

Cuando un bloque de código sincronizado se ejecuta, el objeto es bloqueado y no puede


ser llamado por cualquier otro código hasta que el bloqueo sea liberado:

synchronized void first();


synchronized void second();

De esta manera el beneficio por la sincronización es mayor que colocando la palabra


reservada synchronized antes de un bloque de código.

wait/notify

Además de tener un bloqueo que puede fijarse y luego liberarse,


cada objeto tiene un sistema que le permite hacer una pausa o
esperar (wait) aunque otro hilo tome el bloqueo. Esto permite a
los hilos poder comunicarse la condición de disponible para poder
ejecutarse
Debido a la naturaleza de herencia simple en Java, cada objeto es hijo de una gran clase
ancestro llamado Object desde la cual obtienen la capacidad de comunicación entre
hilos.

wait y notify deben colocarse dentro del código sincronizado para


asegurar que el código actual posee al supervisor de threads.

Una llamada a wait dentro del código sincronizado causa que el hilo active su bloqueo
y se ponga a dormir. Esto normalmente ocurre para permitir a otro hilo obtener el
bloqueo y continuar algún proceso. El método wait es incoherente sin el uso de notify
o notifyAll los cuales permiten que el código que está esperando ser notificado pueda
despertarse y continuar ejecutándose. Un ejemplo típico del uso del protocolo
wait/notify es para permitir la comunicación entre los Hilos que aparentemente
involucran un ciclo infinito, como el siguiente:

//codigo producto
while(true){
try{
wait();
}catch (InterruptedException e) {}
}
// alguna otra accion va aqui
notifyAll();

Como la condición a evaluar es notoriamente verdadera esta permanecerá así, el código a


primera vista muestra que el ciclo será infinito. El método wait sin embargo

162
javaHispano. Tu comunidad, tu lenguaje.

efectivamente significa activa el bloqueo sobre el objeto y espera hasta que el método
notify o notifyAll sea llamado para liberarlo.

La planificación de hilos es dependiente de la implementación y


no puede asegurarse una actuación similar en cada JVM.

A diferencia del resto de Java, la planificación de hilos es dependiente de la plataforma.


Existen dos maneras conocidas para la planificación de hilos:

• Preemtive (Preventivo o apropiativo)


• Time Slicing (Division o fragmentación de tiempos)

En el primer sistema un programa puede "apropiarse" de otro para conseguir su porción


de tiempo de CPU. En el segundo sistema cada hilo consigue un "pedazo" del tiempo de
CPU y entonces se mueve al estado de listo. Esto asegura que un solo hilo no pueda
obtener todo el tiempo del CPU. La desventaja es que no puedes estar seguro cuánto
tiempo tardará un Hilo en ejecutarse. Aunque Java define prioridades para los hilos, de la
mas baja 1 a la más alta que es 10, debes tomar en cuenta que algunas plataformas
reconocerán estas prioridades con precisión pero otras no.

El método notify despertará un hilo que espera ser reactivado por el supervisor de
hilos para el objeto. No puedes estar seguro de qué hilo se levantara. Si tienes sólo un
hilo en espera entonces no tendrás ningún problema. . Si tienes en espera múltiples hilos
entonces se levantara el hilo que lleva más tiempo esperando. Sin embargo no puedes
asegurarlo, ya que las prioridades de los hilos influirán en el resultado. Como resultado
generalmente se te aconseja que uses notifyAll en lugar de notify para no hacer
suposiciones con la planificación o las prioridades. Por supuesto esto no siempre es
posible y tendrás que intentar probar tu código en tantas plataformas como te sea posible.

Preguntas

Pregunta 1)

¿Cuales de las siguientes palabras claves indican a un hilo que libere el objeto que esta
bloqueando?

163
Tutorial para el examen de certificación: SCJP 1.2

1) release
2) wait
3) continue
4) notifyAll

Pregunta 2)

¿Cuál de las siguientes frases define mejor la función de la palabra clave synchronized?

1)Permite que más de un Hilo acceda a un método simultáneamente.


2)Permite que más de un Hilo obtenga el bloqueo de un Objeto sobre una referencia.
3)Da acceso exclusivo al monitor a las palabras clave notify/notifyAll.
4)Significa que sólo un hilo en un momento puede acceder a un método o bloque de
código.

Pregunta 3)

¿Que pasará cuando intentes compilar y ejecutar el siguiente bloque de código?

public class WaNot{


int i=0;
public static void main(String argv[]){
WaNot w = new WaNot();
w.amethod();
}

public void amethod(){


while(true){
try{
wait();
}catch (InterruptedException e) {}
i++;
}//End of while
}//End of amethod

}//End of class

1)Error en tiempo de compilación; no hay una llamada a notify() dentro del método
2)Se compila y ejecuta, pero se crea un ciclo infinito dentro del ciclo while
3)Se compila y ejecuta
4)Se genera un error en tiempo de Ejecución: “IllegalMonitorStatException”

Pregunta 4)

164
javaHispano. Tu comunidad, tu lenguaje.

Cómo puedes especificar qué hilo es el notificado con el protocolo wait/notify

1)Pasando la referencia del objeto como parámetro al método notify


2)Pasando el nombre del método como parámetro al método notify
3)Usando el método notifyAll y pasando la referencia del objeto como referencia
4)Ninguna de las anteriores

Pregunta 5)

¿Cuáles de las siguientes afirmaciones son verdaderas?

1)Java usa un sistema de planificación basado en la división de tiempos para determinar


qué Hilo se ejecutará
2)Java usa un sistema apropiativo cooperativo para determinar qué Hilo se ejecutará
3)La planificación de hilos en Java es dependiente de plataforma y puede variar de una
implementación a otra
4)Tu puedes fijar la prioridad de un hilo en el código

Respuestas

Respuesta 1)

2) wait

Respuesta 2)

4)Significa que sólo un hilo en un momento puede acceder a un método o bloque de


código.

Respuesta 3)

4)Se genera un error en tiempo de Ejecución: “IllegalMonitorStatException”

El protocolo wait/notify se puede usar solamente dentro del código sincronizado. En


este caso la llamada al código no tiene bloqueo sobre el objeto y de esta manera se
generará un error en tiempo de compilación.

Respuesta 4)

4)Ninguna de las anteriores

165
Tutorial para el examen de certificación: SCJP 1.2

El protocolo wait/notify no ofrece un método para especificar que hilo se notificará.

Respuesta 5)
3)La planificación de hilos en Java es dependiente de plataforma y puede variar de una
implementación a otra
4)Tu puedes fijar la prioridad de un hilo en el código

Otras Fuentes para este tema:


Este tema es cubierto en tutorial de Sun:
http://java.sun.com/docs/books/tutorial/essential/threads/waitAndNotify.html

Richard Baldwin Covers lo cubre en:


http://www.geocities.com/Athens/Acropolis/3797/Java058.htm

Jyothi Krishnan en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec7.html#obj24

Bruce Eckel Thinking in Java


Capítulo 14

166
javaHispano. Tu comunidad, tu lenguaje.

Sección 8. El paquete java.awt y su disposición


Objetivo 1.

Escribir código que use las clases administradoras de disposición (Layout Manager) y
los contenedores (Container) de componentes del paquete java.awt para presentar
interfaces graficas de usuario (GUI) con una apariencia especifica, redimensionar su
comportamiento y distinguir las responsabilidades entre los administradores de
disposición y los contenedores.

Nota sobre este objetivo

Aunque el enunciado anterior no lo menciona específicamente, este objetivo involucra un


nuevo tema comparado con el examen para la versión1.1. Éste tema es lo referente al
GridBaglayout. Tiene sentido cubrirlo ya que es un administrador de disposición muy
útil, pero debido a la utilidad que proporciona puede ser un poco complejo su
aprendizaje. Peter va der Linden en su libro "Just Java and Beyond" 3a Edición lo
describe como algo excesivamente complicado y no lo recomienda. Core Java dice: "el
uso de GridBagLayout puede ser increíblemente complejo". Aunque es complejo
utilizarlo de manera manual, varias herramientas de desarrollo como VisualCafe, Visual
Age, JBuilder etc etc. lo hacen más fácil de entender.

Comparando la disposición de componentes de Java y Visual Basic

Comparada con herramientas como Visual Basic o Delphi, Java usa una filosofía distinta
para la disposición de componentes. La mayoría de las herramientas de diseño usan una
filosofía basada en la posición XY de píxeles para colocar un componente. Así en Visual
Basic puedes tomar una caja de texto de la paleta de componentes y colocarla en una
posición especifica en la forma o área de diseño, y esa posición será fija. En contraste
Java usa clases de disposición para controlar donde será colocado un componente de
acuerdo a la pantalla actual.

La filosofía de los administradores de disposición

El administrador de disposición FlowLayout es un buen lugar para empezar ya que es el


administrador de disposición por defecto para los applets. El administrador de
disposición FlowLayout simplemente coloca los componentes sobre el fondo uno
después de otro de izquierda a derecha. Si se acaba el espacio hacia la derecha entonces
envuelve los componentes a la próxima línea

El siguiente código crea una aplicación sencilla y agrega una serie de botones.

167
Tutorial para el examen de certificación: SCJP 1.2

import java.awt.*;
public class FlowAp extends Frame{
public static void main(String argv[]){
FlowAp fa=new FlowAp();
//Change from BorderLayout default
fa.setLayout(new FlowLayout());
fa.setSize(400,300);
fa.setVisible(true);
}
FlowAp(){
add(new Button("One"));
add(new Button("Two"));
add(new Button("Three"));
add(new Button("Four"));
add(new Button("Five"));
add(new Button("Six"));
add(new Button("Seven"));
add(new Button("Eight"));
add(new Button("Nine"));
add(new Button("Ten"));
}//End of constructor
}//End of Application

La siguiente imagen tiene la apariencia por defecto que tendrá la aplicación cuando la
ejecutes desde la línea de comandos:

Apariencia por defecto de la aplicación FlowAp

168
javaHispano. Tu comunidad, tu lenguaje.

Apariencia de la aplicación FlowAp después de redimensionar su tamaño.

Ten presente que ambas imágenes visualizan exactamente el mismo código Java. Lo
único que ha cambiado es la anchura del Frame. El administrador de disposición
FlowLayout automáticamente cambia la disposición de los componentes cuando el
Frame se redimensiona. Si haces el Frame más pequeño FlowLayout cambiaría la
disposición para que los botones se envuelvan alrededor en varias filas.

Cuando te encuentras por primera vez con estos administradores de componentes pueden
parecerte un poco arbitrarios. Algunas herramientas de desarrollo de aplicaciones como
Symantec Visual Café o Borland/Inprise Jbuilder ofrecen maneras para especificar la
posición de los componentes. Para los propósitos del examen por lo menos debes
familiarizarte con el manejo de los administradores de disposición para la creación de
GUI.

Administradores de disposición que debes conocer para el examen.

Para el examen, debes conocer los siguientes administradores de disposición:

• FlowLayout
• BorderLayout
• GridLayout
• GridBagLayout

Responsabilidades de los Administradores de Disposición VS los


Contenedores

169
Tutorial para el examen de certificación: SCJP 1.2

Los contenedores y los administradores de disposición trabajan en equipo. Los


administradores de disposición generalmente controlan donde se colocarán los
componente. Un contenedor controlará la fuente predefinida para estos componentes. Un
componente puede asignarse una fuente especifica para sí mismo. Te pueden dar un texto
que describa la configuración de un contenedor de componentes y preguntarte que color
de fondo y que fuente tendrá un botón o una etiqueta al visualizarse.

Curiosidades del administrador BorderLayout

Si agregas múltiples componentes a un contenedor que utiliza el administrador


BorderLayout pero no pasas una de sus constantes como parámetro (North, South, etc),
puedes conseguir resultados inesperados. Aquí una muestra que ilustra esto:

import java.awt.*;
public class FlowAp extends Frame{
public static void main(String argv[]){
FlowAp fa=new FlowAp();
// fa.setLayout(new FlowLayout());
fa.setSize(400,300);
fa.setVisible(true);
}
FlowAp(){
add(new Button("One"));
add(new Button("Two"));
add(new Button("Three"));
add(new Button("Four"));
add(new Button("Five"));
add(new Button("Six"));
add(new Button("Seven"));
add(new Button("Eight"));
add(new Button("Nine"));
add(new Button("Ten"));
}//End of constructor
}//End of Application

Usando el administrador BorderLayout por defecto

170
javaHispano. Tu comunidad, tu lenguaje.

La razón por la que obtienes este botón grande en el centro es que el administrador de
disposición BorderLayout usa un conjunto de coordenadas al colocar los componentes.
Divide el área de la superficie en:

• North (Norte)
• South (Sur)
• East (Este)
• West (Oeste)
• Center (Centro)

Podrías suponer que el valor por defecto para los componentes cuando los vas colocando
es irse colocando en el sentido de las agujas del reloj alrededor de los puntos de su
circunferencia o en algún otro orden similar. En cambio los diseñadores decidieron hacer
a el centro del área del esquema el valor por defecto. Así en el ejemplo anterior cada
botón se ha colocado encima del botón anterior y ha ocupado enteramente el área
disponible. Como resultado la apariencia es que sólo tienes un botón, el último agregado.

Debido a que el administrador de disposición BorderLayout sólo divide el área en las


cinco coordenadas mencionadas anteriormente, no es el más utilizado de los
administradores de disposición. Sin embargo necesitas conocerlo para el examen y
necesitas ser consciente de que tiene como valor predefinido poner todos los
componentes en el centro.

El administrador de disposición GridLayout

El administrador GridLayout hace aproximadamente lo que esperabas que hiciera.


Divide el área de la superficie en una cuadrícula y cuando agregas componentes los pone
uno después el otro de izquierda a derecha y de arriba hacia abajo. A diferencia de
BorderLayout y de FlowLayout ignora cualquier tamaño predefinido del componente.
Por ejemplo el tamaño predefinido de un botón será el ancho suficiente para mostrar su
texto. El administrador FlowLayout intenta asegurarse que un botón mantenga su
tamaño predefinido. El GridLayout de la única cosa de la que se preocupa es
asegurarse que el componente se ajuste en la cuadrícula

El código siguiente pone un conjunto de botones dentro de un Frame que utiliza un


GridLayout que ha sido fijado para tener 2 filas y 5 columnas.

import java.awt.*;
public class GridAp extends Frame{
public static void main(String argv[]){
GridAp fa=new GridAp();
//definimos el GridLayout con 2 filas y 5 columnas
fa.setLayout(new GridLayout(2,5));
fa.setSize(400,300);

171
Tutorial para el examen de certificación: SCJP 1.2

fa.setVisible(true);
}
GridAp(){
add(new Button("One"));
add(new Button("Two"));
add(new Button("Three"));
add(new Button("Four"));
add(new Button("Five"));
add(new Button("Six"));
add(new Button("Seven"));
add(new Button("Eight"));
add(new Button("Nine"));
add(new Button("Ten"));
}//fin del constructor
}//fin de la Aplicacion

Ejemplo con GridLayout

Observa como los botones son alargados para ocupar todo el espacio disponible del
Frame.

GridBagLayout

Peter van der Linden en su libro Just Java and Beyond describe al administrador de
disposición GridBagLayout como “excesivamente complicado”. Core Java solo dice:
“usar GidBagLayout puede ser increíblemente complicado”. Aunque es complejo
manejarlo manualmente, varias herramientas de desarrollo como Visual Café, Visual
Age, JBuilder, etc. Lo hacen más fácil de usar, sin tener que entenderlo. JBuilder

172
javaHispano. Tu comunidad, tu lenguaje.

modifica fácilmente el método add para incluir los detalles siguientes en una instancia de
la clase GridBagLayout.

add(pAps,new GridBagConstraints2(1, GridBagConstraints.RELATIVE,


GridBagConstraints.RELATIVE, 3, 0.0,
0.0,GridBagConstraints.CENTER,
GridBagConstraints.NONE, new Insets(0,
0, 0, 0), -3, 45));

Pero cuando creas tu código manualmente no necesita parecer tan complejo como este.

Comentarios de las personas que han realizado el examen indican que las preguntas sobre
GridBagLayout no son muy profundas y una comprensión básica de los distintos
campos de la clase GridBagConstraints puede ser adecuada para realizar el examen.

GridBagLayout es un poco parecido a GridLayout sólo que las filas de la cuadrícula


pueden tener alturas diferentes, y las columnas pueden tener anchuras distintas. La
documentación de Java2 viene con un applet de demostración que muestra lo que
puede hacerse con el administrador de disposición GridBagLayout..

Uno de los problemas con el GridBagLayout es que en lugar de estar basado


estrictamente en la cuadrícula subyacente, Java intenta definir las celdas de acuerdo a la
información dada. El administrador de disposición GridBagLayout usa una clase
auxiliar llamada GridBagConstraints que tiene un conjunto de variables miembro
que pueden ajustarse para afectar la apariencia de cada componente agregado. Los
campos que modificas en la clase GridBagConstraints "sugieren" donde irán los
componentes. Una instancia de GridBagConstraints se pasa como un parámetro al
método add, en la forma:

• add(component, GridBagConstraint);

GridBagConstraints contradice la convención general en Java, ya que tu esperarías


poder configurarlo con el método:

setFooParam()

Donde FooParam podría ser el valor X/Y o un relleno entre los componentes.

En cambio toma la forma:

GridBagLayout gbl=new GridBagLayout();


gbl.weightx=100;

173
Tutorial para el examen de certificación: SCJP 1.2

Si usas GridBagLayout sin usar la clase GridBagConstraints éste actúa un poco


como FlowLayout, colocando simplemente uno por uno los componentes en el fondo.

He creado un applet de demostración sencillo con su código fuente que muestra cómo
no cambia la apariencia a menos que juegues con los valores de la clase
GridBagConstraints

http://www.software.u-net.com/applets/GridBagDemo/GridBagTest.htm

El administrador GridBagLayout actúa un poco más como GridLayout si usas las


clases GridBagConstraints y utilizas los campos gridx y gridy para asignar una
posición en una cuadrícula "virtual" para cada componente que agregues. El applet
demuestra esta posibilidad. Esto todavía es un poco torpe y muy parecido a los otros
administradores de disposición. Las cosas empiezan a ponerse mucho más interesante
cuando empiezas a modificar otros campos de la clase GridBagConstraints para
modificar la apariencia de los distintos componentes dentro de esta cuadrícula "virtual".

Recuerda que aunque necesitas entender esto para los propósitos del examen, podría ser
más fácil que cuando estés programando en el mundo real una combinación de controles
de contenedores con otros administradores de disposición. Un ejemplo de cuando esto
no es una buena opción es cuando necesita redimensionar dinámicamente componentes.
Ésta es una situación en donde herramientas de desarrollo como Visual Cafe o JBuilder
no son de mucha ayuda y una buena comprensión del GridBagLayout puede ser
esencial.

He creado un applet de demostración:


http://www.software.u-net.com/applets/GridBagDemo/GridBagDynamic.htm
que muestran el efecto de cambiar los parámetros de relleno dinámicamente para un solo
botón en un grupo de botones desplegados con GridbagLayout

Los campos de la clase GridBagConstraints son:

• gridx gridy
• gridwidth y gridheight
• fill
• ipadx e ipady
• insets
• anchor
• weightx y weighty

Hojeando el excelente libro de Bill Brogdens Java2 Exam Cram, encontré una
demostración comprensiva del GridBagLayout en:

http://www.austria.eu.net/java/programs/applets/missgable/index.htm

174
javaHispano. Tu comunidad, tu lenguaje.

Usando gridx y gridy para sugerir la posición de un componente

Para este ejemplo supondremos que estas escribiendo el código necesario para diseñar el
programa de una agenda. Mostrarás la hora de la cita abajo a la izquierda y los detalles de
la cita abajo a la derecha. Las unidades de tiempo serán de media hora.

Debido que una cita puede cubrir más de una unidad de tiempo; por ejemplo puede durar
una hora y media, necesitaras poder cambiar la altura de los detalles de la cita
dinámicamente para cubrir más de una unidad de tiempo. Debido a este requerimiento, de
tener una altura variante para los detalles de las citas, utilizar GridLayout no es muy
conveniente.

Estarás poniendo paneles en el Frame como contenedores. El primer paso es asegurarse


que cada panel este lado a lado en el Frame principal de la Aplicación.

import java.awt.*;
import java.awt.event.*;
public class GBCal extends Frame{
Panel pTimes=new Panel();
Panel pAps=new Panel();
TextField txTimes=new TextField("09.00");
TextField txAps=new TextField("Meet the boss");
GridBagLayout gbl=new GridBagLayout();
GridBagConstraints gbc=new GridBagConstraints();
public static void main(String argv[]){
GBCal gbc=new GBCal();
gbc.setLayout(new FlowLayout());
}
public GBCal() {
pTimes.add(txTimes);
pAps.add(txAps);
setLayout(gbl);
gbc.gridx=0;
gbc.gridy=0;
pTimes.setBackground(Color.pink);
add(pTimes,gbc);
gbc.gridx=1;
gbc.gridy=0;
pAps.setBackground(Color.lightGray);
add(pAps,gbc);
setSize(300,300);
setVisible(true);
}
}

175
Tutorial para el examen de certificación: SCJP 1.2

Observa cómo las clases GridBagLayout y GridBagConstraints trabajan juntas. La


instancia de GridBagConstraints gbc se reutiliza cada vez que se agrega un
componente. En ningún punto especificas el número de filas y columnas para la
cuadrícula, puesto que la clase GridBagLayout lo deduce de los campos gridx y
gridy de la instancia de la clase GridBagConstraints.

Este es el resultado:

ipadx y ipady para controlar el relleno interior de los componentes

El código ha puesto un color del fondo distinto para que puedas ver la magnitud de cada
panel en lugar de ver simplemente la anchura de los campos de texto. Esto está bien, pero
pensemos que ahora quieres que los campos de texto se estiren y abarquen de izquierda a
derecha todo el Frame de la aplicación principal. Esto se puede realizar modificando el
campo ipadx de la clase GridBagConstraints. Esto puede ejecutarse poniendo:

gbc.ipadx=30;
para las horas y
gbc.ipadx=100;
para los detalles

El código queda:

import java.awt.*;
import java.awt.event.*;

176
javaHispano. Tu comunidad, tu lenguaje.

public class GBCal extends Frame{


Panel pTimes=new Panel();
Panel pAps=new Panel();
TextField txTimes=new TextField("09.00");
TextField txAps=new TextField("Meet the boss");
GridBagLayout gbl=new GridBagLayout();
GridBagConstraints gbc=new GridBagConstraints();
public static void main(String argv[]){
GBCal gbc=new GBCal();
gbc.setLayout(new FlowLayout());
}
public GBCal() {
pTimes.add(txTimes);
pAps.add(txAps);
setLayout(gbl);
gbc.gridx=0;
gbc.gridy=0;
gbc.ipadx=30;
pTimes.setBackground(Color.pink);
add(pTimes,gbc);
gbc.gridx=1;
gbc.gridy=0;
gbc.ipadx=100;
pAps.setBackground(Color.lightGray);
add(pAps,gbc);
setSize(300,300);
setVisible(true);
}
}

y este es el resultado:

177
Tutorial para el examen de certificación: SCJP 1.2

Componentes dentro de un panel utilizando GridBagLayout

Para el próximo paso quiero proporcionar a cada panel su propio administrador de


disposición GridBagLayout y agregar hendiduras para unidades de tiempo adicionales.
Para propósitos de este ejemplo agregaré solo una hendidura de tiempo mas y
simplemente estiraré el cuadro de texto del detalle de la cita para cubrir las hendiduras de
las unidades de tiempo entre las 9.00 y 9.30.

Para hacer esto crearé una nueva instancia de la clase GridBagLayout llamada gbBut y
la usare para preparar la cuadrícula para el panel pTimes para colocar las hendiduras de
las unidades de tiempo una encima de otra verticalmente.

El código para realizar lo anterior es el siguiente:

//Controlar el panel de los tiempos con GridBagLayout


pTimes.setLayout(gbBut);
gbc.gridx=0;
gbc.gridy=0;
pTimes.add(txTimes9,gbc);
gbc.gridx=0;
gbc.gridy=1;
pTimes.add(txTimes930,gbc);

Y este es el código completo:

import java.awt.*;
import java.awt.event.*;
public class GBCal extends Frame{
Panel pTimes=new Panel();
Panel pAps=new Panel();
TextField txTimes9=new TextField("09.00");
TextField txTimes930=new TextField("09.30");
TextField txAps=new TextField("Meet the boss");
GridBagLayout gbl=new GridBagLayout();
GridBagLayout gbBut=new GridBagLayout();
GridBagConstraints gbc=new GridBagConstraints();
public static void main(String argv[]){
GBCal gbc=new GBCal();
gbc.setLayout(new FlowLayout());
}
public GBCal() {
setLayout(gbl);
//Controlar el panel de tiempo con
//GridBagLayout
pTimes.setLayout(gbBut);

178
javaHispano. Tu comunidad, tu lenguaje.

gbc.gridx=0;
gbc.gridy=0;
pTimes.add(txTimes9,gbc);
gbc.gridx=0;
gbc.gridy=1;
pTimes.add(txTimes930,gbc);
pTimes.setBackground(Color.pink);
//Reutilizamos gbc para la disposición del panel principal
gbc.gridx=0;
gbc.gridy=0;
gbc.ipadx=30;
add(pTimes,gbc);
pAps.setLayout(gbBut);
gbc.gridx=0;
gbc.gridy=1;
pAps.add(txAps,gbc);
gbc.gridx=1;
gbc.gridy=0;
gbc.ipadx=100;
pAps.setBackground(Color.lightGray);
add(pAps,gbc);
setSize(300,300);
setVisible(true);
}
}// fin de la clase

El resultado es el siguiente:

Esto esta trabajando bien hasta cierto punto. Tenemos ahora dos hendiduras para las
unidades de tiempo, pero desafortunadamente el espacio para el detalle de la cita tiene

179
Tutorial para el examen de certificación: SCJP 1.2

como valor predefinido el centro del campo de las citas y obtenemos una fila gruesa. Lo
que quiero ahora es fijarla hasta arriba y estirarla para que cubra las dos hendiduras de
tiempo.

Fijando componentes dentro de la cuadrícula

Si un componente no-llena el área completa, puedes especificar en que parte del área lo
quieres usando el campo anchor de la clase GridBagConstraints. Los posibles
valores son:

GridBagconstraints.CENTER
GridBagconstraints.NORTH
GridBagconstraints.NORTHEAST
GridBagconstraints.EAST
GridBagconstraints.SOUTHEAST
GridBagconstraints.SOUTH
GridBagconstraints.SOUTHWEST
GridBagconstraints.WEST
GridBagconstraints.NORTHWEST

En este caso quiero posicionar los campos en la parte superior (North) de los paneles
que los contienen. He aumentado el espesor del campo del detalle de la cita aumentando
el valor de ipady para la dirección del campo.

Aquí esta el código:

import java.awt.*;
import java.awt.event.*;
public class GBCal extends Frame{
Panel pTimes=new Panel();
Panel pAps=new Panel();
TextField txTimes9=new TextField("09.00");
TextField txTimes930=new TextField("09.30");
TextField txAps=new TextField("Meet the boss");
GridBagLayout gbl=new GridBagLayout();
GridBagLayout gbBut=new GridBagLayout();
GridBagConstraints gbc=new GridBagConstraints();
public static void main(String argv[]){
GBCal gbc=new GBCal();
gbc.setLayout(new FlowLayout());
}
public GBCal() {
setLayout(gbl);
//Controlamos el panel de tiempos con GridBagLayout
pTimes.setLayout(gbBut);

180
javaHispano. Tu comunidad, tu lenguaje.

//Aseguramos que los components se coloques


//en la parte superior
gbc.anchor=GridBagConstraints.NORTH;
gbc.gridx=0;
gbc.gridy=0;
pTimes.add(txTimes9,gbc);
gbc.gridx=0;
gbc.gridy=1;
pTimes.add(txTimes930,gbc);
pTimes.setBackground(Color.pink);
//Reutilizamos gbc para el panel principal
gbc.gridx=0;
gbc.gridy=0;
gbc.ipadx=30;
add(pTimes,gbc);
pAps.setLayout(gbBut);
gbc.gridx=0;
gbc.gridy=1;
gbc.ipady=12;
pAps.add(txAps,gbc);
gbc.gridx=1;
gbc.gridy=0;
gbc.ipadx=100;
pAps.setBackground(Color.lightGray);
add(pAps,gbc);
setSize(300,300);
setVisible(true);
}
}//fin de la clase

Y este es el resultado:

181
Tutorial para el examen de certificación: SCJP 1.2

Elementos GridBag no cubiertos por este ejercicio

Este ejercicio ha cubierto los siguientes campos de la clase GridBagConstraints :

• ipadx/y
• gridx/y
• anchor

La clase GridBagConstraints tiene los siguiente campos importantes:

• weightx/y
• fill
• gridwidth/height
• insets

Los campos weightx/y controlan cómo un área crece o se contrae más allá de su
tamaño inicial. Así que si pones el campo weighty a cero el campo seguirá manteniendo
su altura constante aun cuando redimensiones la ventana.

El campo fill controla cómo un componente se estira para llenar el área. Al igual que el
campo anchor puedes definir los valores del campo fill usando constantes ya
definidas de la clase GridBagConstraints. Éstas son:

GridBagConstraints.NONE
GridBagConstraints.HORIZONTAL
GridBagConstraints.VERTICAL
GridBagConstraints.BOTH

Los campos del gridwidth/height determinan cuántas columnas y filas tendrá un


componente.

El campo insets indica el relleno "externo" que tendrá a lo largo de los límites de la
celda de la cuadrícula.

182
javaHispano. Tu comunidad, tu lenguaje.

Preguntas
Pregunta 1)

¿Cuál será la apariencia de un applet con el código siguiente?

import java.awt.*;
public class FlowAp extends Frame{
public static void main(String argv[]){
FlowAp fa=new FlowAp();
fa.setSize(400,300);
fa.setVisible(true);
}
FlowAp(){
add(new Button("One"));
add(new Button("Two"));
add(new Button("Three"));
add(new Button("Four"));
}//fin del constructor
}//fin de la Application

1)Un Frame con botones etiquetados con "One", "Two", "Three","Four" colocados
encada esquina
2)Un Frame con botones etiquetados con "One", "Two", "Three","Four" colocados de
arriba hacia abajo
3)Un Frame con un botón grande etiquetado con "Four" en el Centro
4)Se generará un error al momento de la ejecución indicando que no has puesto un
LayoutManager

Pregunta 2)

¿Cómo indicas dónde se posicionará un componente utilizando Flowlayout?

1)Utilizando las constantes North, South, East, West


2)Asignando una referencia fila/columna
3)Pasando un porcentaje X/Y como parámetro al método add
4)No es necesario indicarlo, el administrador FlowLayout posicionará el componente

183
Tutorial para el examen de certificación: SCJP 1.2

Pregunta 3)

¿Cómo le haces para cambiar al administrador de disposición actual a un contenedor?

1)Usando el método setLayout


2)Una vez creado no puedes cambiar el administrador de disposición de un componente
3)Usando el método setLayoutManager
4)Usando el método updateLayout

Pregunta 4)

¿Qué pasa si agregas una Scrollbar en la parte Norte de un Frame?

1)El Frame se agrandará para permitir que el Scrollbar ocupe su tamaño predefinido.
2)El Scrollbar se colocará en la parte Norte del Frame, será muy ancho, muy grueso y
no muy útil
3)No puedes agregar un Scrollbar en la parte Norte de un Frame, sólo al Este o al
Oeste
4)El Scrollbar se estirará desde arriba hasta abajo del Frame

Pregunta 5)

¿Qué pasa si agregas más botones de los que definiste en un GridLayout y las etiquetas
de cada botón son demasiado largas?

1)El tamaño del contenedor se aumentara para permitir que las etiquetas de cada botón se
desplieguen completamente
2)El GridLayout ignorará el largo de cada etiqueta y éstas se truncarán
3)Se generará un error al compilar indicando que los botones no pueden alcanza su
tamaño predefinido
4)Se generará un error al ejecutarse indicando que los botones no puede alcanzar su
tamaño predefinido

Pregunta 6)

¿Cuales de las siguientes declaraciones son verdaderas?

184
javaHispano. Tu comunidad, tu lenguaje.

1)Puedes controlar la posición un componente llamando al método setLayout(new


GridBagConstraints ())
2)El administrador de disposición FlowLayout puede ser usado para controlar la
posición de componentes utilizando GridBagLayout
3)El administrador de disposición GridBagLayout toma las constantes North,
South, East, West y Center
4)Ninguna de estas respuestas es verdadera

Pregunta 7)

¿Cuales de los siguiente son campos de la clase de GridBagConstraints?

1) ipadx
2) fill
3) insets
4) width

Pregunta 8)

¿Cual será la apariencia mas probable del siguiente código después de ejecutarse?

import java.awt.*;
public class CompLay extends Frame{
public static void main(String argv[]){
CompLay cl = new CompLay();
}
CompLay(){
Panel p = new Panel();
p.setBackground(Color.pink);
p.add(new Button("One"));
p.add(new Button("Two"));
p.add(new Button("Three"));
add("South",p);
setLayout(new FlowLayout());
setSize(300,300);
setVisible(true);
}
}

1)Los botones se colocarán de izquierda a derecha a lo largo de la parte inferior del


Frame
2)Los botones se colocarán de izquierda a derecha a lo largo de la parte superior del
Frame
3)Los botones no se desplegarán

185
Tutorial para el examen de certificación: SCJP 1.2

4)Solo se mostrarán los tres botones ocupando todo el Frame

Pregunta 9)

¿Cuáles de estas declaraciones son ciertas respecto al campo anchor?

1)Es un campo del administrador de disposición GridBagLayout para controlar la


colocación de componentes
2)Es un campo de la clase GridBagConstraints para controlar la colocación de
componentes
3)Una constante valida para el campo anchor es GridBagConstraints.NORTH
4)El campo anchor controla la altura de los componentes agregados a un contenedor

Pregunta 10)
Al usar el administrador de disposición GridBagLayout, cada nuevo componente
agregado requiere una nueva instancia de la clase GridBagConstraints. Es esto :

1)Verdadero
2)Falso

Respuestas

Respuesta 1

3)Un Frame con un botón grande etiquetado con "Four" en el Centro

Si no especificas una constante, cualquier componente agregado a un contenedor que


utilice el administrador de disposición BorderLayout se colocará en el centro. El
administrador de disposición de un Frame por omisión es BorderLayout.

Respuesta 2

4)No es necesario indicarlo, el administrador FlowLayout posicionará el componente

Respuesta 3

1)Usando el método setLayout

Respuesta 4

186
javaHispano. Tu comunidad, tu lenguaje.

2)El Scrollbar se colocará en la parte Norte del Frame, será muy ancho, muy grueso y
no muy útil

Respuesta 5

2)El GridLayout ignorará el largo de cada etiqueta y éstas se truncarán

Respuesta 6

4)Ninguna de estas respuestas es verdadera

Respuesta 7

1) ipadx
2) fill
3) insets

Respuesta 8

2)Los botones se colocarán de izquierda a derecha a lo largo de la parte superior del


Frame

Cuando un administrador de disposición se cambia a FlowLayout el BorderLayout


predefinido no se aplica y el panel se coloca en la parte superior del Frame.

Respuesta 9

2)Es un campo de la clase GridBagConstraints para controlar la colocación de


componentes
3)Una constante valida para el campo anchor es GridBagConstraints.NORTH

Respuesta 10

2)Falso

Otras Fuentes para este tema:


Este tema es cubierto por el tutorial de sun en:
http://java.sun.com/docs/books/tutorial/uiswing/layout/using.html

Richard Baldwin cubre este tema en:


BorderLayout
http://www.geocities.com/Athens/7077/Java114.htm
FlowLayout
http://www.geocities.com/Athens/7077/Java116.htm
GridLayout

187
Tutorial para el examen de certificación: SCJP 1.2

http://www.geocities.com/Athens/7077/Java118.htm
Richard parece no cubrir el GridBagLayout

Jan Newmarsh en Australia a creado esta pagina


http://pandonia.canberra.edu.au/java/xadvisor/gridbag/gridbag.html

Jyothi Krishnan en
http://www.geocities.com/SiliconValley/Network/3693/obj_sec8.html#obj25

188
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 2.

Escribir código que implemente clases oyentes (Listener) y en métodos oyentes extraer
información del evento para determinar el componente afectado ya sea para conocer la
posición actual del ratón o el número de veces que se llama a un evento. Determinar el
nombre de clase de un evento para cualquier interface oyente especificada en el paquete
java.awt.event.

El modelo oyente -Listener- de eventos

Para escribir cualquier aplicación útil con interfaz gráfica de usuario (GUI) utilizando
Java necesitas entender el funcionamiento las clases oyentes y la manera de extraer
información de los eventos que ellas procesan. El sistema de manejo o gestión de eventos
en Java cambió significativamente entre las versiones 1.0x y 1.1. En la versión 1.0x el
código para manejar eventos se parecía bastante al código C llano para Windows, es decir
bastante horrible. Requería la creación de grandes sentencias case donde colocabas el
código para procesar un evento en particular de acuerdo con los parámetros pasados. Este
sistema es bastante sencillo de entender para ejemplos triviales pero no es recomendable
para programas más grandes.

Tengo la impresión de que lo más relevante que necesita saber para el examen es que la
gestión de eventos de la versión 1.1 no es compatible con versiones anteriores. En teoría,
el código escrito con el estilo de código de la versión 1.0x para el manejo de eventos debe
trabajar bien en versiones posteriores del JDK.

El modelo de eventos del JDK 1.1.

El sistema de gestión de eventos de Java 1.1 involucra el uso de clases oyentes -Listener-
que son eficazmente "ligadas" a los componentes para procesar eventos específicosσ.
Esto favorece a las herramientas de desarrollo de aplicaciones GUI para que generen
automáticamente código que maneje los eventos. Si examinas el código generado por una
de estas herramientas puede que te parezca confuso, esto es en parte debido a que tienden
a involucrar clases internas creadas dentro de los métodos. Con el propósito de
aprenderlo puedes manejar las clases de gestión de eventos como si fueran clases de alto
nivel.

Uno de los factores complicados para la gestión de eventos es que ésta se basa en
Interfaces, pero es mucho más fácil de usar utilizando una serie de clases conocidas como
las clases Adaptadoras -Adapter- , qué simplemente implementan las interfaces del
evento. Cuando usas una interface necesitas implementar todos sus métodos, así el uso
directo de la interface EventListener requiere la creación de métodos con cuerpos

σ
NT. El modelo de la versión 1.1 se conoce en algunos documentos como gestión de eventos delegados.

189
Tutorial para el examen de certificación: SCJP 1.2

vacíos para cualquier evento de la interface que no se utilice. Usando las clases
Adaptadoras sólo necesitas crear los cuerpos de los métodos de los eventos que
realmente utilizas.

Las clases Adaptadoras -Adapter- te permiten usar las Interfaces oyentes sin
tener que crear un cuerpo para cada uno de los método de la interface.

Uno de los eventos esenciales más manejados para una aplicación sencilla es la habilidad
de cerrar la aplicación como respuesta a seleccionar la opción cerrar proporcionada por el
sistema operativoγ. Te puede sorprender que el manejo de este evento no venga ya
implementado por omisión en un Frame. Si crea una aplicación que herede un Frame,
pero no creas código para cerrarlo, tendrás qué o bien terminar el proceso desde el gestor
de tareas o, en Windows, ir a la línea de comandos y pulsar CTRL-C.

El equivalente Swing del componente Frame es el JFrame, el JFrame procesa su cierre


como una acción predefinida, pero la certificación no cubre los componentes Swing. El
funcionamiento del Frame de AWT es un buen lugar para comenzar a cubrir el tema de
gestión de eventos.

Los métodos para manejar los eventos de las ventanas (WindowEvent) no son tan
intuitivos como los métodos de otros eventos. Así al principio no es obvio a cual de los
métodos siguientes necesitas responder para cerrar el Frame:

windowClosed o windowClosing

De hecho es el método windowClosing el que necesita ser procesado. La manera más


simple de destruir la ventana es usando la línea:

System.exit(0);

Aquí un ejemplo de una aplicación sencilla que muestra un Frame que responderá
desapareciéndose cuando se accione la opción cerrar proporcionada por el sistema
operativo:

import java.awt.event.*; // necesario para el manejo de eventos


import java.awt.*;
public class ShutHello extends Frame{
public static void main(String argv[]){
ShutHello h = new ShutHello();
}
ShutHello(){

γ
NT: en Windows es la x que aparece en la esquina superior derecha o la pulsación de las teclas ALT-F4

190
javaHispano. Tu comunidad, tu lenguaje.

Button b = new Button("ShutHello");


//creamos una instancia de la clase WindowCloser
WindowCloser wc = new WindowCloser();
//Ligamos el oyente con el programa
addWindowListener(wc);
this.add(b);
setSize(300,300);
setVisible(true);
}
}
class WindowCloser extends WindowAdapter{
//sobreescribimos uno de los metodos del Adaptador
public void windowClosing(WindowEvent e){
System.exit(0);
}
}

La segundo mitad del objetivo pide que conozcas el nombre de clase por cada evento de
cada interface oyente. La tabla que aparece mas adelante lista todas las interfaces oyentes
junto con sus métodos.

Así la interface MouseListener ofrece métodos para los eventos:

• clicked
• pressed
• released
• entered
• exited

Si comparas estos con los eventos manejados en Visual Basic 5 la única área significante
que no se cubre es un conjunto de métodos para manejar los eventos de arrastre con el
ratón(Drag&Drop)

El nombre de la clase del Evento pasado a cada método es bastante intuitivo y basado en
el nombre de la clase Oyente. Así todos los métodos de ActionListener toman un
parámetro de tipo ActionEvent, los métodos de ComponentListener toman un tipo
de ComponentEvent, un ContainerListener toma un ComponentEvent, etc, etc,
etc.

Existen 11 interfaces oyentes en total, pero sólo 7 de ellas tienen múltiples métodos.
Como lo relevante de los adaptadores es eliminar la necesidad de implementar métodos
en blanco, sólo se implementan las clases Adaptadoras para estas 7 Interfaces

Éstas son las siguientes:

• ContainerAdapter

191
Tutorial para el examen de certificación: SCJP 1.2

• FocusAdapter
• KeyAdapter
• MouseAdapter
• MouseMotionAdapter
• WindowAdapter

La siguiente tabla muestra la lista completa de interfaces para gestionar eventos.

Interfaces para la gestión de eventos


ActionListener actionPerformed(ActionEvent) addActionListener()
AdjustmentListener adjustmentValueChanged(AdjustmentEvent) addAdjustmentListener()
ComponentListener componentHidden(ComponentEvent) addComponentListener()
componentMoved(ComponentEvent)
componentResized(ComponentEvent)
componentShown(ComponentEvent)
ContainerListener componentAdded(ContainerEvent) addContainerListener()
componetRemoved(ContainerEvent)
FocusListener focusGained(FocusEvent) addFocusListener()
focusLost(FocusEvent)
ItemListener itemStateChanged(ItemEvent) addItemListener()
KeyListener keyPressed(KeyEvent) addKeyListener()
keyReleased(KeyEvent)
keyTyped(KeyEvent)
MouseListener mouseClicked(MouseEvent) addMouseListener()
mouseEntered(MouseEvent)
mouseExited(MouseEvent)
mousePressed(MouseEvent)
mouseReleased(MouseEvent)
MouseMotionListener mouseDragged(MouseEvent) addMouseMotionListener()
mouseMoved(MouseEvent)
TextListener textValueChanged(TextEvent) addTextListener()
WindowListener windowActivated(WindowEvent) addWindowListener()
windowClosed(WindowEvent)
windowClosing(WindowEvent)
windowDeactivated(WindowEvent)
windowDeiconified(WindowEvent)
windowIconified(WindowEvent)
|windowOpened(WindowEvent)

192
javaHispano. Tu comunidad, tu lenguaje.

Preguntas

Pregunta 1)

¿Cuáles de las siguientes afirmaciones son ciertas?

1)Para un componente dado sus eventos se procesará en el orden en que los oyentes
fueron agregados.
2)Usar las clases Adaptadoras para el manejo de eventos significa crear cuerpos vacíos
para todos los métodos que no se utilicen.
3)Un componente puede tener múltiples oyentes asociados a él
4)Pueden quitarse oyentes una vez agregados.

Pregunta 2)

¿Cuáles de las siguientes líneas son métodos validos para el manejo de eventos?

1) mousePressed(MouseEvent e){}
2) MousePressed(MouseClick e){}
3) functionKey(KeyPress k){}
4) componentAdded(ContainerEvent e){}

Pregunta 3)

¿Que pasara cuando intentes compilar y ejecutar el siguiente código?

import java.awt.*;
import java.awt.event.*;
public class MClick extends Frame implements MouseListener{

public static void main(String argv[]){


MClick s = new MClick();

}
MClick(){
this.addMouseListener(this);
}
public void mouseClicked(MouseEvent e){
System.out.println(e.getWhen());
}
}

1)Se generará un error al compilar.

193
Tutorial para el examen de certificación: SCJP 1.2

2)Se generará un error al ejecutarse.


3)Se compilará y durante su ejecución mostrara la fecha y la hora por cada click
3)Se compilará y durante su ejecución la hora por cada click

Pregunta 4)

¿Cuáles de las siguientes afirmaciones, respecto al manejo de eventos, son verdaderas?

1) El modelo de Eventos de la versión 1.1 es totalmente compatible con modelo de


evento de la versión 1.0
2)El código escrito para el manejo de eventos en la versión 1.0x se ejecutará sin
problemas sobre la versión 1.1 de la JVM.
3)El modelo de Eventos de la versión 1.1 está particularmente ajustado a las
herramientas para la construcción de aplicaciones GUI.
4) El manejo del evento DragDrop fue agregado con la versión 1.1 del modelo de
manejo de eventos.

Respuestas

Respuesta 1)

3)Un componente puede tener múltiples oyentes asociados a él


4)Pueden quitarse oyentes una vez agregados.

Respuesta 2)

1)mousePressed(MouseEvent e){}
4)componentAdded(ContainerEvent e){}

Respuesta 3)

1)Se generará un error al compilar.

Debido a que este código utiliza una interface oyente de eventos, se deben crear cuerpos
vacíos para cada uno de los métodos de la interface.
Este código causará errores que advierten que MClick es una clase abstracta.

Respuesta 4)

2)El código escrito para el manejo de eventos en la versión 1.0x se ejecutará sin
problemas sobre la versión 1.1 de la JVM.
3)El modelo de Eventos de la versión 1.1 está particularmente ajustado a las
herramientas para la construcción de aplicaciones GUI.

194
javaHispano. Tu comunidad, tu lenguaje.

El código para el modelo de manejo de eventos de la versión 1.1 no funcionara con la


versión 1.0x de la JVM. El método DragDrop no existe, yo lo invente.

Otras Fuentes sobre este tema:


Tutorial de Sun
http://java.sun.com/docs/books/tutorial/uiswing/events/intro.html

Richard Baldwin
http://www.Geocities.com/Athens/7077/Java080.htm#design goals of the jdk 1.1 delegation

Jyothi Krishnan
http://www.geocities.com/SiliconValley/Network/3693/obj_sec8.html#obj25

David Reilly
http://www.davidreilly.com/jcb/java107/java107.html

195
Tutorial para el examen de certificación: SCJP 1.2

Sección 9. El paquete java.lang.Math


Objetivo 1.

Escribir código que utilice los siguientes métodos de la clase java.lang.Math: abs,
ceil, floor, max, min, random, round, sin, cos, tan y sqrt.

Nota sobre este objetivo

La clase java.lang.Math tiene el modificador final, por consiguiente sus métodos


son estáticos. Esto significa que no puedes heredar la clase para crear o modificar las
versiones de estos métodos. Esto es probablemente favorable ya que reduce la posibilidad
de ambigüedad. Con certeza encontraras preguntas sobre estos métodos y sería una
verdadera pena que no las contestes correctamente simplemente porque los pasaste por
alto.

abs

Hasta que comencé ha estudiar para el examen de certificación no tenía ni idea de lo que
hace el método abs. Elimina el signo de un número y retorna el numero simplemente.
Así la siguiente línea de código mostrará simplemente 99. Si el número es positivo
obtendrás como resultado el mismo número.

System.out.println(Math.abs(-99));

ceil

Este método retorna el próximo número entero hacia arriba. Si tienes lo siguiente:

ceil(1.1)

El resultado sea 2.0.

Si cambias lo anterior por:

ceil(-1.1)

el resultado será -1

196
javaHispano. Tu comunidad, tu lenguaje.

floor

De acuerdo a la documentación del JDK este método devuelve:

El valor double más grande que no sea mayor que el argumento pasado y que sea igual a
un entero.

Si tienes aun dudas de lo que significa lo anterior, aquí hay un pequeño programa y sus
resultados:

public class MyMat{


public static void main(String[] argv){
System.out.println(Math.floor(-99.1));
System.out.println(Math.floor(-99));
System.out.println(Math.floor(99));
System.out.println(Math.floor(-.01));
System.out.println(Math.floor(0.1));
}
}

los resultados son:

-100.0
-99.0
99.0
-1.0
0.0

max y min

Toma nota de lo siguiente: los siguientes dos métodos toman dos parámetros. Puedes
encontrar preguntas con ejemplos incorrectos que les pasan sólo un parámetro. Como
podrías esperar estos métodos son el equivalente de decir:

"Cual es más grande: ESTE parámetro o ESTE parámetro"

El siguiente código muestra como funcionan estos métodos:

public class MaxMin{


public static void main(String argv[]){
System.out.println(Math.max(-1,-10));
System.out.println(Math.max(1,2));
System.out.println(Math.min(1,1));
System.out.println(Math.min(-1,-10));
System.out.println(Math.min(1,2));
}
}

197
Tutorial para el examen de certificación: SCJP 1.2

Estos son los resultados:

-1
2
1
-10
1

random

Retorna un número aleatorio entre 0.0 y 1.0 (0.0 <=n<1)

A diferencia de algunos sistemas que generan números aleatorios Java no parece ofrecer
la funcionalidad de pasar un número como semilla para aumentar la aleatoriedad.

Para propósitos del examen uno de los aspectos importantes a considerar de este método
es que el valor de retorno está entre 0.0 y 1.0. Así los resultados de una típica secuencia
de ejecuciones podrían ser:

0.9151633320773057
0.25135231957619386
0.10070205341831895

A menudo un programa necesita producir un número aleatorio entre 0 y 10 o 0 y 100. El


código siguiente combina código matemático para producir un número aleatorio entre 0 y
100.

System.out.println(Math.round(Math.random()*100));

round

Redondea al entero más cercano. Para qué, si el valor tiende más de la mitad hacia el
entero más alto, el valor es redondeado al entero siguiente. En caso contrario el valor
retornado es el entero anterior. Si por ejemplo el valor a redondear es x entonces:

2.0 <=x < 2.5. entonces Math.round(x)==2.0


2.5 <=x < 3.0 entonces Math.round(x)==3.0

Aquí hay otros ejemplo con sus resultados:

System.out.println(Math.round(1.01));
System.out.println(Math.round(-2.1));
System.out.println(Math.round(20));

198
javaHispano. Tu comunidad, tu lenguaje.

1
-2
20

sin cos tan

Estos métodos elegantes toman un parámetro de tipo double y hacen justo las mismas
funciones elegantes que realizarían en cualquier otro lenguaje que hayas usado. En mi
caso, que son 12 años de programación, nunca he usado una de estas funciones. Así
quizás lo único que debemos recordar es que el parámetro que recibe es de tipo double.

sqrt

Retorna un valor tipo double que es la raíz cuadrada del valor pasado como parámetro.

Resumen

Los métodos max y min toman dos parámetros


El método random retorna un valor entre 0 y 1
El método abs elimina el signo del valor pasado como parámetro
El método round redondea un numero eliminando así la parte que esta
después del punto decimal, pero conserva el signo del número.

Pregunta 1)

¿Cuales de las siguientes líneas se compilarán correctamente?

1) System.out.println(Math.max(x));
2) System.out.println(Math.random(10,3));
3) System.out.println(Math.round(20));
4) System.out.println(Math.sqrt(10));

199
Tutorial para el examen de certificación: SCJP 1.2

Pregunta 2)

¿Cuál de las siguientes líneas mostrara un valor aleatorio con valor entre 1 y10?

1) System.out.println(Math.round(Math.random()* 10));
2) System.out.println(Math.round(Math.random() % 10));
3) System.out.println(Math.random() *10);
4) Ninguna de las anteriores

Pregunta 3)

¿Cuál será la salida de la siguiente línea?

System.out.println(Math.floor(-2.1));

1) -2
2) 2.0
3) -3
4) -3.0

Pregunta 4)

¿Cuál será la salida de la siguiente línea?

System.out.println(Math.abs(-2.1));

1) -2.0
2) -2.1
3) 2.1
4) 1.0

Pregunta 5)

¿Cuál será la salida de la siguiente línea?

System.out.println(Math.ceil(-2.1));

1) -2.0
2) -2.1

200
javaHispano. Tu comunidad, tu lenguaje.

3) 2.1
3) 1.0

Pregunta 6)

¿Qué pasará cando intentes compilar y ejecutar el siguiente código?

class MyCalc extends Math{


public int random(){
double iTemp;
iTemp=super();
return super.round(iTemp);
}
}
public class MyRand{
public static void main(String argv[]){
MyCalc m = new MyCals();
System.out.println(m.random());
}
}

1)Se generará un error al compilarse


2)Se generará un error al ejecutarse
3)Se ejecutará y mostrara un valor aleatorio entre 0 y 1
4) Se ejecutará y mostrara un valor aleatorio entre 1 y 10

Respuestas

Respuesta 1)

3) System.out.println(Math.round(20));
4) System.out.println(Math.sqrt(10));

La opción 1 es incorrecta porque el método max recibe dos parámetros no uno, y la


opción 2 es incorrecta ya que el método random recibe solo un parámetro no dos

Respuesta 2)

4) Ninguna de las anteriores

La opción más cercana a la correcta es la 1 pero el detalle esta en recordar que el método
random incluye el 0 y la pregunta pide valores entre 1 y 10.

201
Tutorial para el examen de certificación: SCJP 1.2

Respuesta 3)

4) -3.0

Respuesta 4)

3) 2.1

Respuesta 5)

1) -2.0

Respuesta 6)

1)Se generará un error al compilarse

La clase Math tiene el modificador final y por eso no puede ser heredada.

Otras Fuentes para este tema


Jyothi Krishnan en
http://www.geocities.com/SiliconValley/Network/3693/obj_sec9.html#obj28

202
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 2

Nota sobre este objetivo

La teoría de la inmutabilidad de la clase String dice que una vez creado, un String
nunca puede modificarse. En nuestra experiencia programando con Java en la vida real
nos damos cuenta que esto no es del todo cierto.

Veamos el siguiente código:

public class ImString{


public static void main(String argv[]){
String s1 = new String("Hello");
String s2 = new String("There");
System.out.println(s1);
s1=s2;
System.out.println(s1);
}
}

¿Si un String no puede cambiarse entonces s1 debería mostrar siempre "Hello" , pero
si pruebas el código te darás cuenta que en la segunda ejecución del println se muestra
la cadena "There". Entonces ¿Que pasa?

La inmutabilidad se refiere realmente a los puntos de referencia de los Strings. Cuando


se asignan s2 a s1 en el ejemplo, el String que contiene "Hello" deja de ser
referenciado y ahora s1 apunta a la misma referencia que s2. De hecho la cadena "Hola"
realmente no se ha modificado es solo que teóricamente ya no puedes "llegar a ella".

El objetivo te pide que reconozcas las implicaciones de la inmutabilidad de las cadenas, y


la principal parece ser qué si quieres eliminar y cambiar el contenido de cadenas de texto
debes utilizar la clase StringBuffer que viene construida con más métodos para esos
propósitos.

Debido a que la concatenación de Strings causa que un nuevo String sea instanciado
"fuera de escena", puede haber un desempeño poco eficiente si estás manipulando
grandes cantidades de Strings, como sucede al leer un archivo con gran cantidad de
texto. Generalmente la inmutabilidad de la clase String no altera nuestra programación
diaria, pero se cuestionará en el examen. Recuerda que de cualquier manera que te hagan
la pregunta, una vez creado un String no puede cambiarse aún cuando la referencia a él
se cambie para apuntar a algún otro String. Aunque ni los objetivos específicos del

203
Tutorial para el examen de certificación: SCJP 1.2

examen para Java2 ni para Java 1.1 lo mencionan, estoy bastante seguro que algunas
preguntas requieren conocimiento sobre la clase StringBuffer.

Preguntas

Pregunta 1)

Has creado dos Strings que contienen nombres. Así:

String fname="John";
String lname="String"

¿Cómo puedes cambiar estos Strings para que tomen nuevos valores dentro del mismo
bloque de código?

1)
fname="Fred";
lname="Jones";

2)
String fname=new String("Fred");
String lname=new String("Jones");

3)
StringBuffer fname=new StringBuffer(fname);
StringBuffer lname=new StringBuffer(lname);

4) Ninguna de las anteriores

Pregunta 2)

Estás creando un programa para leer en archivo del texto de 8 MB. Cada nueva línea
leída se agrega a un objeto String pero te estás dando cuenta que, tristemente, le falta
desempeño. ¿Cuál es probablemente la explicación?

204
javaHispano. Tu comunidad, tu lenguaje.

1)El sistema de Entrada/Salida(I/O) de Java se diseña alrededor de un común


denominador de mas bajo nivel y es inherentemente lento

2)La clase String es inapropiada para operaciones de I/O, un arreglo de caracteres


sería más conveniente.

3)Debido a que los Strings son inmutables un nuevo String se crea con cada línea
leída, Cambiándolo por un StringBuffer puedes aumentar el desempeño.

4)Ninguna de las anteriores.

Respuestas

Respuesta 1)

4) Ninguna de las anteriores

Una vez creado un String sólo se puede leer y no puede modificarse.

Respuesta 2)

3)Debido a que los Strings son inmutables un nuevo String se crea con cada línea
leída, Cambiándolo por un StringBuffer puedes aumentar el desempeño.

Espero que ninguno de los programadores en C hayan sugerido un arreglo de


caracteres.

Otras Fuentes para este tema:


Este tema es cubierto en el tutorial de Sun en:
http://java.sun.com/docs/books/tutorial/essential/strings/stringsAndJavac.html
(no entra mucho en detalle)

Jyothi Krishnan cubre este tema en:


http://www.geocities.com/SiliconValley/Network/3693/obj_sec9.html#obj29

205
Tutorial para el examen de certificación: SCJP 1.2

Sección 10. El paquete java.util


Objetivo 1.

Hacer una selección apropiada de las clases/interfaces de colecciones para satisfacer


requisitos de comportamientos específicos

Nota sobre este objetivo

Aunque no lo menciona específicamente, este objetivo involucra uno de los nuevos


objetivos para la versión del examen de Java 2, conocer las clases de colecciones. Lo
que el examen cuestiona sobre estas nuevas clases es bastante básico, pide un
conocimiento sobre donde y cómo podrías usarlas, en lugar de conocer detalladamente
sus campos y métodos.

Las colecciones antiguas

La API Java 2 incluye nuevas interfaces y clases para reforzar las colecciones ya
disponibles. Las primeras versiones de Java incluyeron:

vector
hashtable
array
BitSet

De éstos, sólo el array era incluido en los objetivos para el examen de certificación de la
versión 1.1. Una de las omisiones notables de Java 1.1 era el soporte para ordenar, un
requisito muy común en cualquier situación de programación.

Las nuevas colecciones

La raíz de la API de colecciones es la interface Collection. Esta te proporciona


una serie de métodos comunes que tendrán todas las clases de colecciones.
Probablemente nunca crearas tu propia clase para implementar la interface Collection
ya que Java te proporciona una serie de subclases y clases que usan esta interface.

Java 2 incluye las siguiente nuevas clases de colecciones:

Sets
Maps

Y una nueva clase llamada Set.

206
javaHispano. Tu comunidad, tu lenguaje.

Las clases que implementan la interface Collection más que almacenar tipos de datos
primitivos, almacenan objetos. Todo esto tiene inconvenientes ya que la creación de
objetos reduce el rendimiento y a los elementos antes de usarse se les aplica un cast, al
tipo apropiado, para que puedan ser utilizarlos. Esto también significa que las colecciones
no verifican que los elementos sean todos el mismo tipo, ya que un objeto puede ser casi
cualquier cosa.

Set

Set es una interface de colecciones que no puede contener elementos duplicados. De esta
manera se presta para manejar conceptos como el de un conjunto de registros retornados
de una base de datos relacional. Parte de la magia de la interface Set esta en el método
add.

add(Object o)

Cualquier objeto pasado al método add puede implementar el método equals para que
el valor pueda compararse con objetos existentes en la clase. Si la clase ya contiene éste
objeto la llamada al método add no modifica el contenido y retorna false. La idea de
retornar false cuando intentas agregar un elemento que ya existe se parece más a la
manera en que trabaja C/C++ que la manera en que trabaja Java. La mayoría de los
métodos similares en Java lanzan una Excepción en este tipo de situaciones.

List

List es una interface de colecciones ordenadas que puede contener elementos


duplicados.

Algunos de sus métodos más importantes son:

add
remove
clear

La documentación de JDK da como ejemplo usar List para manejar una GUI que
controle una lista que contiene todos los nombres de los Planetas.

Map

Map es una interface, las clases que la implementen no pueden tener llaves duplicadas y
es similar a Hashtables.

¿Por qué utilizar colecciones en lugar de arreglos?

207
Tutorial para el examen de certificación: SCJP 1.2

La gran ventaja de las colecciones sobre los arreglos es que las colecciones son
desarrollables , es decir, no tienes que asignarles un tamaño al momento de crearlas. El
inconveniente de las colecciones es que sólo guardan objetos y no tipos primitivos e
inevitablemente afectan el rendimiento de la aplicación. Los arreglos no soportan
directamente el ordenamiento, pero esto puede ser superado usando los métodos estáticos
de las colecciones. Aquí hay un ejemplo:

import java.util.*;
public class Sort{
public static void main(String argv[]){
Sort s = new Sort();
}
Sort(){
String s[] = new String[4];
s[0]="z";
s[1]="b";
s[2]="c";
s[3]="a";
Arrays.sort(s);
for(int i=0;i< s.length;i++)
System.out.println(s[i]);
}
}

Las colecciones Set y Map aseguran la individualidad de sus elementos, List no


asegura esta individualidad pero permite que sus elementos se ordenen.

Usando Vectores

El siguiente ejemplo muestra cómo puedes agregar objetos de diferentes clases a un


Vector. Esto contrasta con los arreglos donde cada elemento debe ser del mismo tipo.
El código avanza por cada objeto mostrando su contenido. Al mostrarse el contenido,
implícitamente se accede al método toString() de cada objeto.

import java.awt.*;
import java.util.*;
public class Vec{
public static void main(String argv[]){
Vec v = new Vec();
v.amethod();
}//fin de main
public void amethod(){

208
javaHispano. Tu comunidad, tu lenguaje.

Vector mv = new Vector();


//nota como un Vector puede almacenar
//objetos de distintos tipos
mv.addElement("Hello");
mv.addElement(Color.red);
mv.addElement(new Integer(99));

//la siguiente linea causaría un error


//ya que un vector no almacena tipos primitivos
//mv.addElement(99)
//Ahora avanzamos por cada elemento del vector
for(int i=0; i< mv.size(); i++){
System.out.println(mv.elementAt(i));
}
}//fin de amethod
}

Antes de Java2 el uso de la clase del Vector era la manera principal de crear una
estructura de datos re-dimensionable. Los elementos de esta clase pueden quitarse con el
método remove .

Usando Hashtables

Las Hashtables son parecidas al concepto en Visual Basic de una colección que usa
una llave. Actúa como un Vector, sólo que en lugar de referirte a los elementos por un
número, te refieres a ellos por una llave. La palabra hash de su nombre se refiere a un
término matemático que hace referencia al manejo de índices. Una Hashtable puede
ofrecer un beneficio superior sobre un Vector, su rapidez

BitSet

Un BitSet como su nombre lo indica, almacena una secuencia de bits. No te confundas


por la parte "set" de su nombre, no es un conjunto matemático o algo relacionado con
bases de datos, tampoco se relaciona con los conjuntos(Sets) disponibles en Java2. Es
más apropiado pensar en él como un vector de bits. Un BitSet puede ser útil para el
almacenamiento eficaz de bits, en donde los bits se usen para representar los valores de
true/false. La alternativa de usar alguna clase de colecciones que contenga valores
tipo Boolean puede ser menos eficaz.

Según Bruce Eckel en “Thinking in Java”

Sólo es eficaz desde el punto de vista del tamaño; si estás buscando un acceso eficaz, es
ligeramente más lento que el uso de un arreglo de algún tipo primitivo.

209
Tutorial para el examen de certificación: SCJP 1.2

Un BitSet es un poco una clase novedosa de la que nunca puedes llegar a necesitar.
Sospecho que podría ser conveniente para propósitos criptográficos o para el
procesamiento de imágenes. Por favor avísame si te encuentras con alguna pregunta
relacionada con esta clase en el examen.

Pregunta 1)

¿Cuáles de las siguientes clases son colecciones?

1) Collection
2) Iterator
3) HashSet
4) Vector

Pregunta 2)

¿Cuáles de los siguientes enunciados son verdaderos respecto a la interface


Collection?

1)La clase Vector a sido modificada para implementar la interface Collection


2)La interface Collection ofrece métodos individuales y métodos colectivos como
addAll
3)La interface Collection es compatible con versiones anteriores y todos sus métodos
están disponibles dentro de las clases del JDK 1.1.
4)Las clases de colecciones hacen innecesario el uso de arreglos.

Pregunta 3)

¿Cuáles de las siguientes declaraciones son verdaderas?

1)La interface Set se diseño para asegurar que la implementación de clases tengan
miembros únicos
2)Las clases que implementan la interface List no pueden contener elementos
duplicados

210
javaHispano. Tu comunidad, tu lenguaje.

3) la interface Set se diseño para almacenar registros retornados de una consulta a una
base de datos
4) la Interface Map no es parte del marco de trabajo de las colecciones

Pregunta 4)

¿Cuáles de las siguientes declaraciones son verdaderas?

1) los elementos de clase de colecciones pueden ser ordenados usando el método sort de
la interface Collection
2)Puedes crear una colección ordenada instanciando una clase que implemente la
interface List
3)El método sort de la interface Collection toma como parámetros una A o una D
para indicar el orden, Ascendente/Descendente
4)Los elementos de una clase de colecciones pueden ser ordenados usando el método
order de la interface Collection

Pregunta 5)

Deseas almacenar una cantidad pequeña de datos y hacerlos disponibles para un acceso
rápido. No necesitaras que los datos sean ordenados, la singularidad no es un problema y
los datos permanecerán bastante estáticos ¿Qué estructura de datos podría ser la mas
conveniente para este requisito?

1)TreeSet
2)HashMap
3)LinkedList
4)Un arreglo

Pregunta 6)

¿Cuales de las siguientes son clases Collection?

1) ListBag
2) HashMap
3) Vector
4) SetList

211
Tutorial para el examen de certificación: SCJP 1.2

Pregunta 7)

¿Cómo puedes remover un elemento de un Vector?

1)Con el Método delete


2)Con el Método cancel
3)Con el Método clear
4)Con el Método remove

Respuestas

Respuesta 1)

3) HashSet
4) Vector

Las otras 2 son interfaces.

Respuesta 2)

1)La clase Vector a sido modificada para implementar la interface Collection


2)La interface Collection ofrece métodos individuales y métodos colectivos como
addAll

Las clases de colecciones son nuevas en Java 2. Con excepción de las clases que han sido
actualizadas como Vector y BitSet, si ejecutas cualquiera de las Colecciones a través
de un JDK antiguo, conseguirás un error en tiempo de compilación.

Respuesta 3)

1)La interface Set se diseño para asegurar que la implementación de clases tengan
miembros únicos

Los elementos de una clase que implementa la interface List pueden contener elementos
duplicados. Aunque una clase que implementa la interface Set podría usarse para
guardar archivos retornados por una consulta a una base de datos, no se diseño
particularmente para ese propósito.

Respuesta 4)

2)Puedes crear una colección ordenada instanciando una clase que implemente la
interface List

Respuesta 5)

212
javaHispano. Tu comunidad, tu lenguaje.

4)Un arreglo

Para semejante requisito sencillo probablemente un arreglo será la mejor solución.

Respuesta 6)

2) HashMap
3) Vector

A partir de Java 2 la clase Vector fue actualizado para ser parte del marco de trabajo de
las colecciones.

Respuesta 7)

4)Con el Método remove

Otras Fuentes para este tema:


El tutorial de SUN
http://java.sun.com/docs/books/tutorial/collections/index.html

Jyothi Krishnan cubre este tema en


http://www.geocities.com/SiliconValley/Network/3693/obj_sec10.html#obj30

213
Tutorial para el examen de certificación: SCJP 1.2

Sección 11. El paquete java.io


Objetivo 1

Escribir código que utilice objetos de la clase File para navegar dentro del sistema de
archivos.

En su excelente libro "Just Java and Beyond" Peter van der Linden comienza su capítulo
sobre I/O de ficheros diciendo:

"No es justo remarcar, como han hecho algunos, que el soporte para I/O en Java es un
punto muy importante".

Yo creo que él estaba indicando que es levemente importante, y así, es un área en la que
hay que redoblar la comprobación de tu conocimiento antes de ir al examen. Cuando lo
estas aprendiendo te queda al menos la compensación de que comprenderás un área útil
del lenguaje.

El sistema I/O de java esta basado en el concepto de flujos – streams – . El termino


computacional stream fue popularizado primeramente por el sistema operativo UNÍX y
puedes considerar tomarlo como analogía de un flujo de agua. Puedes tener un stream
viniendo de una sola salida y de ahí aplicarle un filtro para procesarlo.

Los nombres de las clases de flujos de I/O no son intuitivos y las cosas no siempre
funcionan como las podrías imaginar.

La clase File

La clase File no es del todo descriptiva, puesto que una instancia de la clase File
representa el nombre de un archivo o directorio más que el archivo en si mismo.

Mi primera suposición al pedírseme navegar en un sistema de archivos sería buscar un


método para cambiar de directorio. Desafortunadamente la clase File no tiene ése método
y parece que simplemente tienes que crear una nueva instancia de File con un directorio
diferente en su constructor.

Así el examen podría hacerte preguntas sobre la habilidad de crear y eliminar archivos y
directorios, qué podría ser considerado bajo la cabecera de "navegación por el sistema de
ficheros".

Crear una instancia de la clase File no crea un archivo en el sistema operativo


subyacente.

214
javaHispano. Tu comunidad, tu lenguaje.

La clase File ofrece el método:

delete()

Para borrar un archivo o directorio.

mkdir() y mkdirs()

Para crear directorios.

La clase File contiene el método list(), que devuelve un arreglo de String´s


conteniendo todos los archivos de un directorio. Esto es muy practico para comprobar si
un archivo esta disponible antes de intentar abrirlo. Un ejemplo del uso de list():

import java.io.*;
public class FileNav{
public static void main(String argv[]){
String[] filenames;
File f = new File(".");
filenames = f.list();
for(int i=0; i< filenames.length; i++)
System.out.println(filenames[i]);
}
}

Esto sencillamente muestra una lista de todos los archivos en el directorio actual ("*.*")

Independencia de plataforma

La clase File esta escrita en Java puro. Esto significa que no incluye código nativo, pero
también significa que esta escrito para funcionar independientemente de la plataforma
sobre la cual se ejecute. Debido a las diferencias en la manera en que trabajan los
distintos sistemas de archivos es importante estar consciente de particularidades de la
plataforma como el carácter separador de los directorios. En Win/DOS es la barra
invertida “\” , en UNÍX es la barra normal “/” y sobre MAC es otro. Puedes saber cual es
este carácter dependiente de la plataforma utilizando la constante File.separator en
lugar de obtenerlo con alguna codificación compleja.

Un programa para navegar por el sistema de archivos

El siguiente archivo es bastante largo (más de 90 líneas) pero para entenderlo, necesitaras
conocer la mayoría de los objetivos que se explican en esta sección. El programa te
permite navegar entre los archivos de un directorio y cambiar de directorio. Esta
inspirado en parte en código del libro "Java in a Nutshell" de O´reilly. Un libro que
recomiendo ampliamente. Aquí una muestra del programa en funcionamiento.

215
Tutorial para el examen de certificación: SCJP 1.2

import java.awt.*;
import java.awt.event.*;
import java.io.*;
public class Filer extends Frame implements ActionListener{
/**************************************************************
Marcus Green October 2000 Part of the Java Programmer Certification
tutorial available at http://www.jchq.net. Addressing the objective to
be able to use the File class to navigate the File system.This program
will show a list of files in a directory .Clicking on a directory will
change to the directory and show the contentsNote the use of
File.separator to allow this to work on Unix or PC (and maybe even the
Mac)
****************************************************************/
List lstFiles;
File currentDir;
String[] safiles;
int iEntryType = 6;
int iRootElement = 0;
int iElementCount = 20;

public static void main(String argv[]){


Filer f = new Filer();
f.setSize(300,400);
f.setVisible(true);
}

216
javaHispano. Tu comunidad, tu lenguaje.

Filer(){
setLayout(new FlowLayout());
lstFiles = new List(iElementCount);
lstFiles.addActionListener(this);
//set the current directory
File dir = new File(System.getProperty("user.dir"));
currentDir = dir;
listDirectory(dir);
add(lstFiles);
addWindowListener(
new WindowAdapter(){
public void windowClosing(WindowEvent e){
System.exit(0);
}

} );

public void actionPerformed(ActionEvent e){


int i = lstFiles.getSelectedIndex();
if(i==iRootElement){
upDir(currentDir);
}else{
String sCurFile = lstFiles.getItem(i);
//Find the length of the file name and then
//chop of the filetype part (dir or file)
int iNameLen = sCurFile.length();
sCurFile = sCurFile.substring(iEntryType,iNameLen);
File fCurFile = new File(currentDir.toString()+File.separator +
sCurFile);
if(fCurFile.isDirectory()){
listDirectory(fCurFile);
}
}

}
public void upDir(File currentDir){
File fullPath = new File(currentDir.getAbsolutePath());
String sparent = fullPath.getAbsoluteFile().getParent();
if(sparent == null) {
//At the root so put in the dir separator to indicate this
lstFiles.remove(iRootElement);
lstFiles.add(" "+File.separator+" ",iRootElement);
return;
}else{
File fparent = new File(sparent);
listDirectory(fparent);
}
}
public void listDirectory(File dir){
String sCurPath = dir.getAbsolutePath()+File.separator ;
//Get the directorie entries
safiles = dir.list();
//remove the previous lis and add in the entry
//for moving up a directory

217
Tutorial para el examen de certificación: SCJP 1.2

lstFiles.removeAll();
lstFiles.addItem("[ .. ]");
String sFileName = new String();
//loop through the file names and
//add them to the list control
for(int i=0; i< safiles.length; i++){
File curFile = new File(sCurPath + safiles[i]);
if(curFile.isDirectory()){
sFileName = "[dir ]" + safiles[i];
}else{
sFileName = "[file]"+safiles[i];
}
lstFiles.addItem(sFileName);
}
add(lstFiles);
currentDir=dir;
}

Preguntas
Pregunta 1)
¿Cuál de los métodos siguientes sirve para distinguir entre un directorio y un archivo?

1) FileType()
2) isDir()
3) isDirectory()
4) getDirectory()

Pregunta 2)
¿Cuál de los siguientes métodos de la clase File borrará un directorio o un archivo al
ejecutarse?

1) La clase File no te permite borrar un archivo o un directorio


2) remove()
3) delete()
4) del()

Pregunta 3)

218
javaHispano. Tu comunidad, tu lenguaje.

Cómo puedes obtener los nombres de los archivos contenidos dentro de una instancia de
la clase File con el contenido del directorio actual

1) dir.list()
2) dir.list
3) dir.files()
4) dir.FileNames()

Pregunta 4)

¿Cuál de las siguientes líneas llenará una instancia de la clase File con el contenido del
directorio actual?

1) File f = new File();


2) File f = new File("*.*");
3) File f = new File('*.*');
4) File f = new File(".");

Pregunta 5)

Dada la siguiente línea de código:

File f = new File("myfile.txt");

¿Qué método creará el archivo “myfile.txt” en el sistema operativo subyacente?

1) f.write();
2) f.close();
3) f.flush();
4) Ninguno de los anteriores

Pregunta 6)

¿Cuál de las siguientes líneas cambiará el directorio actual al que se encuentra en un nivel
superior?

1) chDir("..");
2) cd(".");
3) up();
4) Ninguno de los anteriores

Pregunta 7)

219
Tutorial para el examen de certificación: SCJP 1.2

¿Cuáles de los siguientes son métodos o campos de la clase File?

1) getParent()
2) separator
3) dirname
4) getName();

Respuestas
Respuesta 1)

3) isDirectory()

Respuesta 2)

3) delete()

Respuesta 3)

1) dir.list()

El método list retorna un arreglo de String´s que contendrá el contenido del directorio
actual.

Respuesta 4)

4) File f = new File(".");

Este constructor para la clase File obtendrá el contenido del directorio actual sobre
sistemas de archivos como DOS o UNIX, pero no estoy seguro que ocurrirá sobre otros
sistemas con una estructura de archivos exótica como Mac OS.

Respuesta 5)

4) Ninguno de los anteriores

La clase File principalmente describe un archivo que debe de existir. Para crear un
archivo en el sistema operativo subyacente necesitas pasar una instancia de la clase File
a una instancia de una de las clases OutputStream.

Respuesta 6)

4) Ninguno de los anteriores

220
javaHispano. Tu comunidad, tu lenguaje.

Java no tiene una manera directa para cambiar el directorio actual. Una manera indirecta
es crear una nueva instancia de la clase File apuntando al directorio deseado.

Respuesta 7)

1) getParent()
2) separator
4) getName();

Otras Fuentes para este tema:


Puedes darle un vistazo a los ejemplos del libro de I/O de O'Reilly:
http://metalab.unc.edu/javafaq/books/javaio/index.html
Este tema se cubre en el tutorial de SUN en
http://java.sun.com/docs/books/tutorial/essential/io/
La API de la clase File
http://java.sun.com/products/jdk/1.2/docs/api/java/io/File.html
El JLS sobre IO, un poco académico
http://www.infospheres.caltech.edu/resources/langspec-1.0/javaio.doc.html
Richard Baldwin sobre I/O
http://home.att.net/~baldwin.rg/Intermediate/Java060.htm
Joyothi tiene varias útiles tablas sobre las clases de I/O en
http://www.geocities.com/SiliconValley/Network/3693/io.html

221
Tutorial para el examen de certificación: SCJP 1.2

Objetivo 2

Escribir código que use objetos de las clases InputStreamReader y


OutputStreamWriter para traducir entre códigos de caracteres UNICODE y el nativo
de plataforma o el ISO 8859-1.

Me sorprendió que este objetivo no se enfatizara en el examen de JDK 1.2 puesto que se
había introducido la internacionalización y ésta es una de las grandes características de
Java. Es bonito vender software a mil millones de europeos y americanos pero mil
millones de chinos serían un agradable mercado adicional (incluso si sólo el 10% lo
compran) Éste es el tipo de objetivo con el que ni siquiera los programadores de Java
experimentados pueden tener poca experiencia, ¡Así qué toma nota!.

Codificación de caracteres en Java: UTF y UNICODE

Java utiliza dos sistemas muy parecidos de codificación UTF y UNICODE. Java fue
diseñado desde abajo para tenérselas que ver con caracteres multibyte y puede tratar con
inmensos números de caracteres que pueden guardarse usando el sistema de codificación
UNICODE. Los caracteres UNICODE son almacenados en 2 bytes permitiendo
almacenar arriba de 65K caracteres. Esto le permite ser usado con alfabetos no
occidentales. Esto significa que puede manipular chino y japonés, y casi cualquier otro
conjunto de caracteres conocido. Estarás agradecido de saber que no tienes que dar
ejemplos de nada de esto en el examen.

Aunque UNICODE puede representar casi cualquier carácter que llegues a usar en tu vida,
no es un método eficiente de codificación para programar. La mayoría del texto dentro de
un programa usa el código ASCII, la mayoría de este puede guardarse fácilmente dentro
de un byte. Por razones de tamaño, Java utiliza un sistema de codificación llamado UTF-
8 para las literales de cadena, identificadores y otro texto dentro del programa. Esto
puede dar como resultado un ahorro considerable de espacio comparándolo con el uso de
UNICODE donde cada carácter requiere 2bytes.

Las clases StreamReader

La clase StreamReader convierte una entrada de bytes (no relacionada con un


conjunto de caracteres) en un flujo de entrada de caracteres, uno que tenga el concepto de
conjunto de caracteres.

Si solo te las tienes que ver con conjuntos de caracteres de tipo ASCII, probablemente
solo usarás clases Reader en la forma de:

InputStreamReader(InputStream in)

222
javaHispano. Tu comunidad, tu lenguaje.

Esta versión usa el código de caracteres nativo de la plataforma. En el JDK1.1 este valor
por defecto se identifica por medio de la propiedad del sistema file.encoding. La
codificación predeterminada generalmente es ISO-Latin 1 excepto en Mac donde es
MacRoman. Si esta propiedad del sistema no esta definida, el identificador del código
estándar es 8859_1 (ISO-LATIN-1). La suposición parece ser: si todo lo demás falla,
debes volver al inglés. Experimentar con otros juegos de caracteres es problemático,
debido que los caracteres no pueden mostrarse correctamente si el entorno no se
configura apropiadamente. Así si intentas mostrar un carácter del conjunto de caracteres
chinos tu sistema quizá no lo soportará

Si te las tienes que ver con otros conjuntos de caracteres puedes usar

InputStreamReader(InputStream in, String encoding);

Las clases StreamReader y Writer pueden tomar cualquier codificación de


caracteres como parámetro o puedes usar la codificación predeterminada.

Recuerda que el InputStream viene primero y el código de caracteres después.

Los métodos read y write

La clase InputStreamReader tiene un método llamado read() y la clase


OutputStreamWriter tiene un método llamado write() que permiten leer y escribir
caracteres respectivamente. Cuando se llama al método read este lee bytes desde el
stream de entrada y los convierte a caracteres UNICODE usando la codificación
especificada en el constructor del stream. Cuando se llama al método write() los
caracteres que vienen del stream son convertidos en su correspondiente byte codificado y
es almacenado en un buffer interno. Cuando el buffer se llena, el contenido se escribe en
el stream de bytes de salida.

Ejemplo. GreekWriter

El código para esta clase escribe un archivo de salida contiene algunas letras en alfabeto
griego.

Si intentas abrir el archivo Out.txt con un editor, veras algo parecido a basura.

import java.io.*;

class GreekWriter {
public static void main(String[] args) {
String str = "\u03B1\u03C1\u03B5\u03C4\u03B7";
try {
Writer out = new OutputStreamWriter(

223
Tutorial para el examen de certificación: SCJP 1.2

new FileOutputStream("out.txt"), “8859_7");


// 8859_7 is the ISO code for ASCII plus greek,
// although this
// example also works on my machine if it is set to UTF8
out.write(str);
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

Ejemplo. GreekReader

import java.io.*;
import java.awt.*;

class GreekReader extends Frame{


/*******************************************************
*Companion program to GreekWriter to illustrate
*InputStreamReader and OutputStreamWriter as part
*of the objectives for the Sun Certified Java Programmers
*exam. Marcus Green 2000
*********************************************************/
String str;
public static void main(String[] args) {
GreekReader gr = new GreekReader();
gr.go();
gr.setWin();
}
public void go(){

try {
FileInputStream fis = new FileInputStream("out.txt");
InputStreamReader isr = new InputStreamReader(fis,"8859_7");
Reader in = new BufferedReader(isr);

StringBuffer buf = new StringBuffer();


int ch;
while ((ch = in.read()) > -1) {
buf.append((char)ch);
}
in.close();
str = buf.toString();

} catch (IOException e) {
e.printStackTrace();
}

public void paint(Graphics g) {


//paint method automatically called by the system
Insets insets = getInsets();
int x = insets.left, y = insets.top;
//Add 30 to y or we will only see the

224
javaHispano. Tu comunidad, tu lenguaje.

//downstrokes of the letters


g.drawString(str, x, y +30);
}
public void setWin(){
//Nice big font so we can see the characters.
Font font = new Font("Monospaced", Font.BOLD, 59);
setFont(font);
setSize(200,200);
setVisible(true);
//Show the frame
show();
}

GreekReader en ejecución.

Preguntas
Pregunta 1)
¿Cuales de las siguientes sentencias son verdaderas?

1) La clase OutputStream debe tomar una codificación de caracteres como parámetro


para su constructor.
2) La codificación predefinida para la clase OutputStreamWriter es ASCII
3) Las clases InputStreamWriter y OuputStreamWriter puede tomar como
parámetro para su constructor una codificación de caracteres.
4) La clase InputStreanReader puede tomar un stream como uno de sus
constructores.

Pregunta 2)
¿Cuales de las siguiente sentencias son verdaderas?

225
Tutorial para el examen de certificación: SCJP 1.2

1) Java puede desplegar conjuntos de caracteres independientemente del sistema


operativo subyacente.
2) La clase InputStreamReader puede tomar una instancia de otra clase
InputStream como constructor.
3) Un InputStreamReader puede actuar como constructor de un
OutputStreamReader para hacer conversiones entre juegos de caracteres.
4) Java usa el código ASCII para almacenar cadenas internamente.

Pregunta 3)
¿Cuales de las siguientes son firmas validas para la clase InputStreamReder?

1) InputStreamReader(InputStream in, String encoding);


2) InputStreamReader(String encoding,InputStream in);
3) InputStreamReader(String encoding,File f);
4) InputStreamReader(InputStream in);

Pregunta 4)
¿Cuales de los siguientes son métodos de la clase InputStreamReader?

1) read()
2) write()
3) getBuffer()
4) getString()

Pregunta 5)
¿Cuales de las siguientes son sentencias son verdaderas?

1) Java utiliza UNICODE para almacenar internamente literales de cadena


2) Java utiliza ASCII para almacenar internamente literales de cadena
3) Java utiliza UTF-8 para almacenar internamente literales de cadena
4) Java utiliza la codificación nativa de la plataforma para almacenar internamente
literales de cadena

Respuestas

Respuesta 1)
2) La codificación predefinida para la clase OutputStreamWriter es ASCII
4) La clase InputStreanReader puede tomar un stream como de sus constructores.

Respuesta 2)

1) Java puede desplegar conjuntos de caracteres independientemente del sistema


operativo subyacente.
2) La clase InputStreamReader puede tomar una instancia de otra clase
InputStream como constructor.

226
javaHispano. Tu comunidad, tu lenguaje.

Aunque Java puede guardar caracteres independientemente del sistema operativo


subyacente, el conjunto de caracteres apropiado debe instalarse para poder desplegar esos
caracteres. Generalmente los streams son unidos con otros streams, por ejemplo un
InputStream toma como constructor a otro InputStream y un OutputStream toma
como constructor a otro OutputStream. Java utiliza el sistema de codificación UTF
para almacenar internamente cadenas.

Respuesta 3)

1) InputStreamReader(InputStream in, String encoding);


4) InputStreamReader(InputStream in);

Si no especificas una codificación la JVM asumirá como codificación la predeterminada


de la plataforma.

Respuesta 4)

1) read()

Respuesta 5)

3) Java utiliza UTF-8 para almacenar internamente literales de cadena

Otras Fuentes para este tema:


La documentación de Sun sobre las clases InputStreamReader y OutputStreamWriter:
http://java.sun.com/products/jdk/1.2/docs/api/java/io/OutputStreamWriter.html
http://java.sun.com/products/jdk/1.2/docs/api/java/io/InputStreamReader.html

JavaCaps:
http://www.javacaps.com/sjpc_io_obj2.html

Todo lo que puedes querer saber sobre UNICODE:


http://www.unicode.org/

227
Tutorial para el examen de certificación: SCJP 1.2

Objetivo 3

Distinguir entre las condiciones bajo las cuales se usaría conversión al código nativo de
plataforma y las condiciones bajo las cuales se usaría una conversión específica.

Este podría ser un objetivo de "bondad y disciplina". Con esto quiero decir que algunos
puritanos podrían tomar la actitud de que siempre deberías especificar el código de
conversión de caracteres porque nunca sabes donde, cuando y como se usará tu
programa. Esto es porque muchos programadores asumieron que su código nunca tendría
que vérselas con el problema del año 2000 por el que hubo tanto lío. Bien, es un buen
pago para algunos programadores.

Si tomas un punto de vista más benigno, este objetivo te pide identificar si tu código esta
preparado para enfrentarse a un código de caracteres no estándar. Si tu código de
caracteres por defecto no es ISO-LATIN-1 y consideras que el inglés es el lenguaje
estándar para los negocios, o si necesitas manipular distintos códigos de caracteres,
entonces aprovéchate de la posibilidad de hacer conversiones específicas.

Si algo de esto no significa nada para ti, vuelve a leer la sección anterior sobre las clases
de lectura y escritura de archivos.

Otras Fuentes para este tema:


La documentación de Sun sobre la internacionalización:
http://java.sun.com/docs/books/tutorial/i18n/text/stream.html
http://java.sun.com/products/jdk/1.1/docs/guide/intl/
http://java.sun.com/docs/books/tutorial/i18n/index.html

228
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 4
Seleccionar los argumentos validos para los constructores de una lista de clases
contenidas en el paquete java.io.

El énfasis en este objetivo es que conozcas los argumentos validos para los constructores
de estas clases. Lo mas relevante que se puede mencionar es que la clase RandomFile
no toma algún stream como argumento para alguno de sus constructores.

Estas clases toman instancias de otros streams como argumentos. Así en el examen te
pueden preguntar si alguna de ellas puede tomar una instancia de la clase File, un
String con el nombre del archivo o la ruta del archivo, para ver si realmente conoces los
argumentos válidos para sus constructores. Un constructor valido será algún tipo de
stream más otros posibles parámetros.

FileInputStream and OutputStream

Las clases FileInputStream y FileOuputStream tomen como parámetro principal


para sus constructores alguna referencia a un archivo. Esta puede ser un String que
contenga el nombre del archivo, una instancia de la clase File o una instancia de la clase
FileDescriptor. Estas clases a menudo se utilizan como el primer paso para ligar
clases de streams. Típicamente una instancia de la clase FileInputStream recibe una
referencia a un archivo-cualquiera de las que mencionamos anteriormente-, y se conecta
con una instancia de la clase InputStreamReader para leer los caracteres que contiene
dicho archivo. Este es un ejemplo de como se liga la clase FileInputStream con la
clase InputStreamReader.

Este programa mostrará su propio código fuente.

import java.io.*;
public class Fis{
public static void main(String argv[]){
try{
FileInputStream in = new FileInputStream("Fis.java");
InputStreamReader isr = new InputStreamReader(in);
int ch=0;
while((ch = in.read())> -1){
StringBuffer buf = new StringBuffer();
buf.append((char)ch);
System.out.print(buf.toString());
}
} catch (IOException e){System.out.println(e.getMessage());}
}
}

Lo anterior es aconsejable cuando programas en el “mundo real” y utilizas la clase


InputStreamReader, este tipo de situaciones te permite implementa fácilmente la

229
Tutorial para el examen de certificación: SCJP 1.2

internacionalización. Observa el ejemplo GreekReader.java mostrado anteriormente para


ver un ejemplo de esto.

BufferedInputStream y BufferedOutputStream
Estas clases descienden directamente de las clases FilterInputStream y
FilterOutputStream respectivamente. Permiten leer más información de manera
inmediata colocándola en un buffer. Esto incrementa la eficiencia, ya que es mucho más
rápido leer desde la memoria que desde el disco. Este tipo de lectura es particularmente
útil si tienes que estar leyendo una gran cantidad de datos. Un ejemplo puede ser cuando
estés procesando varias decenas de Megabytes de texto. Las clases
BufferedInputStream y BufferedOutputStream toman una instancia de las clases
InputStream y OutputStream respectivamente como parámetro para alguno de sus
constructores, pero también pueden tomar un parámetro adicional que defina el tamaño
del buffer. Así, puedes ajustar el tamaño del buffer que vas a utilizar.

Este es un ejemplo de uso de las clases BufferedInputStream, observa como el


código es similar con el ejemplo anterior únicamente se substituye la línea del
InputStreamReader por BufferedInputStream.

import java.io.*;
public class BufIn{
public static void main(String argv[]){
try{
FileInputStream fin = new FileInputStream("BufIn.java");
BufferedInputStream bin = new BufferedInputStream(fin);
int ch=0;
while((ch=bin.read())> -1){
StringBuffer buf = new StringBuffer();
buf.append((char)ch);
System.out.print(buf.toString());
}

}catch(IOException e){System.out.println(e.getMessage());};
}
}

DataInputStream y DataOutputStream

Las clases DataInputStream y DataOuputStream se usan para leer de una manera


portable representaciones binarias de los tipos de datos primitivos de java. Esto te da
acceso a varios métodos como readDouble o readInt que funcionarán de la misma
manera sobre distintas plataformas. En el JDK 1.0 está era una de las principales maneras
de acceder a texto UNICODE, pero desde la versión 1.1 del JDK ha sido substituido por
las clases Reader . Esas clases toman una instancia de la clase Stream como parámetro
de su constructor.

230
javaHispano. Tu comunidad, tu lenguaje.

El siguiente ejemplo escribe un carácter en un archivo y después lo lee y muestra en la


consola.

//Write the file


import java.io.*;
public class Dos{
public static void main(String argv[]){
try{
FileOutputStream fos = new FileOutputStream("fos.dat");
DataOutputStream dos = new DataOutputStream(fos);
dos.writeChar('J');
}catch(IOException e){System.out.println(e.getMessage());}
}
}

//Read the file


import java.io.*;
public class Dis{
public static void main(String argv[]){
try{
FileInputStream fis= new FileInputStream("fos.dat");

DataInputStream dis = new DataInputStream(fis);


System.out.println(dis.readChar());
}catch(IOException e){System.out.println(e.getMessage());}
}
}

La clase File
La clase File tiene tres versiones de constructores. Estos son:

File(String path);
File(String path, String name)
File(File dir, String name);

Los tres son muy similares y realizan la misma función. El primer constructor que toma
un String recibe el nombre de un archivo, incluyendo su ruta, en forma de cadena.
Esta ruta puede ser absoluta o relativa. El segundo toma por separado la ruta y el nombre
del archivo y el tercer constructor es casi igual al primero excepto que el primer
parámetro que indica el directorio del archivo es del tipo File en lugar del tipo String.

RandomAccesFile
Lo más importante que debes saber sobre los constructores de esta clase, es que toman 2
parámetros para sus constructores y que el segundo parámetro es un String que
contiene el modo de apertura del archivo. Más adelante se explica con detalle.

231
Tutorial para el examen de certificación: SCJP 1.2

Preguntas
Pregunta 1)

¿Cuáles de las siguientes clases con parámetros validos para los constructores de la clase
FileInputStream?

1) File
2) String
3) FileDescriptor
4) RadomAccessFile

Pregunta 2)

¿Cuáles de los siguientes constructores son validos para la clase BufferedInputStream?

1) BufferedInputStream(FileInputStream in, int size)


2) BufferedInputStream(FileInputStream in)
3) BufferedInputStream(FileOutputStream fos)
4) BufferedInputStream(RandomAccessFile ram)

Pregunta 3)

¿Cuáles de los siguientes constructores son validos para la clase DataInputStream?

1) DataInputStream(FileInputStream in, int size)


2) DataInputStream(FileInputStream in)
3) DataInputStream(File f)
4) DataInputStream(String s)

Pregunta 4)

Dado el siguiente código:


import java.io.*;
public class Dos{
public static void main(String argv[]){
FileOutputStream fos = new FileOutputStream("fos.dat");
DataOutputStream dos = new DataOutputStream(fos);
BufferedOutputStream bos = new BufferedOutputStream(dos);

232
javaHispano. Tu comunidad, tu lenguaje.

dos.write('8');
}
}

¿Cuál de las siguientes sentencias es verdadera?

1) El código no se compilará
2) No compilará debido a que la clase BufferedOutputStream no tiene un constructor
que tome como parámetro una instancia de la clase DataOutputStream
3) Se compilara y escribirá el byte 8 en el archivo
4) Se compilara y escribirá la cadena “8” en el archivo

Pregunta 5)

¿Cuáles de los siguientes son constructores validos?

1) File(String path);
2) File(String path, String name)
3) RandomAccessFile(File)
4) File(RandomAccesFile name)

Pregunta 6)

Dado el siguiente código:

import java.io.*;
public class Ppvg{
public static void main(String argv[]){
Ppvg p = new Ppvg();
p.go();
}

public void go(){


try{
DataInputStream dis = new DataInputStream(System.in);
dis.read();
}catch(Exception e){}
System.out.println("Continuing");
}
}

¿Cuál de las siguientes sentencias es verdadera?


1) El código se compilará y al ejecutarse se detendrá hasta que se pulse una tecla
2) El código no se compilará debido a que System.in es una clase estática
3) El código se compilará y se ejecutará sin generar ninguna salida
4) El código no se compilará debido a que System.in no es parámetro para un
constructor valido para la clase DataInputStream

Respuestas

233
Tutorial para el examen de certificación: SCJP 1.2

Respuesta 1)

1) File
2) String
3) FileDescriptor

Respuesta 2)

1) BufferedInputStream(FileInputStream in, int size)


2) BufferedInputStream(FileInputStream in)

Respuesta 3)

2) DataInputStream(FileInputStream in)

Respuesta 4)

1) El código no se compilará

El código no se compilará debido a que no se encuentra dentro de un bloque try/catch

Respuesta 5)

1) File(String path);
2) File(String path, String name)

Respuesta 6)

1) El código se compilará y al ejecutarse se detendrá hasta que se pulse una tecla

Otras Fuentes para este tema


La documentación de las API´s en SUN
Buffered I/O
http://java.sun.com/products/jdk/1.2/docs/api/java/io/BufferedInputStream.html
http://java.sun.com/products/jdk/1.2/docs/api/java/io/BufferedOutputStream.html

Data I/O
http://java.sun.com/products/jdk/1.2/docs/api/java/io/DataInputStream.html
http://java.sun.com/products/jdk/1.2/docs/api/java/io/DataOutputStream.html

234
javaHispano. Tu comunidad, tu lenguaje.

Objetivo 5

Escribir el código adecuado para leer, escribir o actualizar ficheros usando objetos
FileInputStream, FileOutputStream y RandomAccessFile.

FileInputStream and FileOutputStream

El siguiente ejemplo crea un fichero de texto llamado Out.txt y escribe el texto "Hello" en
él. Si abres el fichero resultante verás que contiene el texto "H e l l o" (con un espacio en
blanco entre cada letra). Sospecho que es porque un carácter en Java es de 16 bits y uno
en ASCII son 8 bits, los 8 bits de más peso dan como resultado un carácter en blanco.

Esto también muestra el objetivo previo de usar la clase DataOutputstream, descendiente


de FilterOutputStream. Esto permite que sean escritos los caracteres legibles para el ser
humano. Si este ejemplo solo usara métodos de FileOutputStream estarías limitado a
escribir bytes o enteros. Si haces esto y muestras el resultado por la consola, solo verás
caracteres extraños.

import java.io.*;
public class Fos{
String s = new String("Hello");
public static void main(String argv[]){
Fos f = new Fos();
f.amethod();
}

public void amethod(){


try{
FileOutputStream fos = new
FileOutputStream("Out.txt");
//DataOutputStream te permite escribir caracteres
DataOutputStream dos = new DataOutputStream(fos);
dos.writeChars(s);
}catch(IOException ioe) {}
}
}

El siguiente ejemplo leerá el fichero de texto producido en el ejemplo anterior y mostrará


el texto en la consola. Date cuenta de que puesto que el programa anterior generó el
fichero como UNICODE, si creas un fichero de texto con un editor de textos conteniendo
una cadena de caracteres como "Hello", el siguiente código probablemente sólo
mostrará caracteres extraños.

import java.io.*;
public class Fis{

235
Tutorial para el examen de certificación: SCJP 1.2

public static void main(String argv[]){


Fis f = new Fis();
f.amethod();
}

public void amethod(){


try{
FileInputStream fis = new
FileInputStream("Out.txt");
DataInputStream dis = new DataInputStream(fis);
while(true){
char c =dis.readChar();
System.out.println(c);
}
}catch(IOException ioe) {}
}
}

RandomAccessFile

La clase RandomAccessFile esta desarrollada libremente y no encaja fácilmente dentro


de las clases de flujos de I/O. Si en el examen encuentras respuestas que mezclan
instancias de RandomAccessFile con otros flujos de datos, casi seguramente son
respuestas erróneas.

El constructor de RandomAccessFile toma una instancia de la clase File o una


cadena de caracteres, y un argumento indicando el modo de apertura. El argumento
referente al modo de apertura puede ser "r" para solo lectura o "rw" para lectura y
escritura. Memoriza estas dos opciones, que no te engañen en el examen con modos
como "w", "ro" o "r+w";

A diferencia de la clase File, si intentas pasar el nombre de un archivo al constructor,


RandomAccessFile intentará abrir el archivo. Si pasas únicamente el modo "r" como
parámetro y el archivo no existe se lanzará una excepción. Y si pasas como parámetro el
modo "rw" se intentará crear el archivo desde el sistema operativo.

La clase RandomAccessFile no toma un stream como un parámetro para


alguno de sus constructores..

Este ejemplo leerá el fichero Out.txt creado por el ejemplo anterior Fos.java.

Por culpa del byte superior en blanco (byte, no bit), el resultado muestra un signo de
interrogación con cada letra.

236
javaHispano. Tu comunidad, tu lenguaje.

import java.io.*;
public class Raf{
public static void main(String argv[]){
Raf r = new Raf();
r.amethod();
}

public void amethod(){


try{
RandomAccessFile raf = new
RandomAccessFile("Out.txt","rw");
for(int i=0; i<10;i++){
raf.seek(i);
char myc = raf.readChar();
//? mostrado para los bytes de mas peso, los superiores
System.out.println(myc);
}
} catch(IOException ioe) {}
}
}

Pregunta 1)

Asumiendo que se ha escrito código para el manejo de excepciones, ¿Cuáles de las


siguientes sentencias creará una instancia de la clase RandomAccessFile?

1)RandomAccessFile raf = new RandomAccessFile("myfile.txt","+rw");


2)RandomAccessFile raf = new RandomAccessFile( new DataInputStream());
3)RandomAccessFile raf = new RandomAccessFile("myfile.txt");
4)RandomAccessFile raf = new RandomAccessFile( new File("myfile.txt"));

Pregunta 2)

¿Cuales de las siguientes sentencias son verdaderas?

1) La clase RandomAccessFile permite moverte hacia adelante y hacia atrás de un


archivo sin tener que re-abrirlo.
2) Una instancia de la clase RandomAccessFile puede ser usada como parámetro para
un constructor de la clase FileInputStream

237
Tutorial para el examen de certificación: SCJP 1.2

3) Los métodos de la clase RandomAccessFile no lanzan excepciones


4) Crear una instancia de la clase RandomAccessFile lanzará una excepción si el
archivo no existe

Pregunta 3)
¿Cuales de las siguientes sentencias son verdaderas?

1) La Clase FileInputStream puede tomar el nombre de un archivo o una instancia de


la clase File como parámetros para alguno de sus constructores
2) La Clase FileInputStream lanzará una excepción si el nombre del archivo pasado
como parámetro al constructor no existe.
3) Los métodos de la clase FileInputStream son apropiados especialmente para
manipular archivos de texto.
4) El método delete de la clase FileInputStream elimina un archivo desde el
sistema operativo.

Pregunta 4)

¿Que pasará cuando intentes compilar y ejecutar el siguiente código?

import java.io.*;
public class Fos{
String s = new String("Hello");
public static void main(String argv[]){
Fos f = new Fos();
f.amethod();
}

public void amethod(){


FileOutputStream fos = new
FileOutputStream("Out.txt");
fos.write(10);
}
}

1) Error al compilar
2) Error al ejecutar
3) Se creará un archivo llamado Out.txt conteniendo el texto "10"
4) Se creará un archivo llamado Out.txt

Pregunta 5)
¿Cuales de las siguientes sentencias son verdaderas?

1) El método seek de la clase FileInputStream define la posición actual del puntero


del archivo.
2) El método read de la clase FileinputStream lee un número definido de bytes.
3) El método get de la clase FileInputStream lee un número definido de bytes.

238
javaHispano. Tu comunidad, tu lenguaje.

4) Una instancia de la clase FileOuputStream se puede cerrar utilizando en método


close.

Respuestas

Respuesta 1)

1) RandomAccessFile raf = new RandomAccessFile("myfile.txt","+rw");

La clase RandomAccessFile es una anomalía en la arquitectura de I/O de Java. Desciende


directamente de Object y no es parte de la arquitectura de flujos de datos.

Respuesta 2)

1) La clase RandomAccessFile permite moverte hacia adelante y hacia atrás de un


archivo sin tener que re-abrirlo.
4) Crear una instancia de la clase RandomAccessFile lanzará una excepción si el
archivo no existe.

Respuesta 3)

1) La Clase FileInputStream puede tomar el nombre de un archivo o una instancia de


la clase File como parámetro para alguno de sus constructores
2) La Clase FileInputStream lanzará una excepción si el nombre del archivo pasado
como parámetro al constructor no existe.

Las clases FileInputStream y FileOutputStream están diseñadas para leer y


escribir bytes más que texto.

Respuesta 4)

1) Error al compilar

Fos.java:10: Exception java.io.IOException must be caught, or it must be declare in the throws


clause of this method. FileOutputStream fos = new FileOutputStream("Out.txt");

Respuesta 5)

2) El método read de la clase FileinputStream lee un número definido de bytes.


4) Una instancia de la clase FileOuputStream se puede cerrar utilizando en método
close.

239
Tutorial para el examen de certificación: SCJP 1.2

Otras Fuentes para este tema


Este tema esta cubierto por el tutorial de Sun en
http://java.sun.com/docs/books/tutorial/essential/io/

El JLS sobre Java IO, un poco académico


http://www.infospheres.caltech.edu/resources/langspec-1.0/javaio.doc.html

Richard Baldwin sobre I/O


http://home.att.net/~baldwin.rg/Intermediate/Java060.htm

O’reilly ha publicado un libro específico sobre Java I/O. Probablemente entra en más
detalle que el necesario para el examen de certificación pero navegar por los ejemplos
online te puede ayudar. El libro tiene generalmente buenas críticas en www.amazon.com

http://www.oreilly.com/catalog/javaio/

Joyothi tiene varias útiles tablas sobre las clases de I/O en


http://www.geocities.com/SiliconValley/Network/3693/io.html

240

You might also like