Tutorial SCJP12

240
Tutorial para el Examen de certificacion: SCJP 1.2 Traducción del tutorial de Marcus Green. RuGI Isaac Ruiz Guerra [email protected] javaHispano Tu lenguaje, tu comunidad. Versión Julio del 2003.

Transcript of Tutorial SCJP12

Page 1: Tutorial SCJP12

Tutorial para el Examen de certificacion: SCJP 1.2

Traducción del tutorial de Marcus Green.

RuGI Isaac Ruiz Guerra

[email protected]

javaHispano Tu lenguaje, tu comunidad.

Versión Julio del 2003.

Page 2: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

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 [email protected] 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/).

Page 3: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

3

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

Page 4: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

4

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

Page 5: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

5

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

Page 6: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

6

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

Page 7: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

7

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];

Page 8: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

8

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; }

Page 9: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

9

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.

Page 10: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

10

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();

Page 11: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

11

} 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.

Page 12: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

12

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)

Page 13: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

13

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”};

Page 14: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

14

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

Page 15: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

15

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.

Page 16: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

16

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

Page 17: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

17

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"); } }

Page 18: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

18

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)

Page 19: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

19

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 }

Page 20: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

20

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 }

Page 21: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

21

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.

Page 22: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

22

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

Page 23: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

23

//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

Page 24: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

24

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();

Page 25: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

25

} 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"

Page 26: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

26

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)

Page 27: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

27

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"); } } }

Page 28: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

28

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"); } }

Page 29: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

29

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.

Page 30: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

30

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.

Page 31: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

31

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.

Page 32: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

32

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{

Page 33: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

33

^ 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.

Page 34: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

34

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

Page 35: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

35

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.

Page 36: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

36

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(); } }

Page 37: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

37

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"); }

Page 38: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

38

} 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.

Page 39: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

39

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?

Page 40: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

40

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.

Page 41: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

41

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

Page 42: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

42

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

Page 43: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

43

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; }

Page 44: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

44

}

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[]){

Page 45: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

45

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

Page 46: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

46

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

Page 47: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

47

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:

Page 48: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

48

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.

Page 49: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

49

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 ?

Page 50: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

50

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;

Page 51: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

51

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"

Page 52: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

52

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.

Page 53: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

53

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)

Page 54: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

54

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

Page 55: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

55

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)

Page 56: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

56

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.

Page 57: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

57

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

Page 58: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

58

}//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);

Page 59: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

59

} }//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[]){

Page 60: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

60

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++){

Page 61: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

61

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

Page 62: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

62

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

Page 63: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

63

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

Page 64: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

64

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

Page 65: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

65

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{}

Page 66: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

66

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)

Page 67: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

67

¿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{}

Page 68: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

68

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"); }

Page 69: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

69

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); } }

Page 70: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

70

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

Page 71: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

71

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)

Page 72: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

72

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.

Page 73: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

73

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.

Page 74: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

74

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.

Page 75: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

75

Ú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

Page 76: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

76

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;

Page 77: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

77

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:

Page 78: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

78

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{} }

Page 79: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

79

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:

Page 80: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

80

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.

Page 81: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

81

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

Page 82: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

82

}//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

Page 83: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

83

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)

Page 84: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

84

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

Page 85: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

85

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)

Page 86: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

86

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

Page 87: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

87

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.

Page 88: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

88

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

Page 89: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

89

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

Page 90: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

90

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.

Page 91: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

91

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

Page 92: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

92

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{

Page 93: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

93

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

Page 94: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

94

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

Page 95: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

95

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”.

Page 96: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

96

Declarando 18 como un literal entero

Decimal 18

Octal 022 (Cero no la 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

Page 97: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

97

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.

Page 98: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

98

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"); } }

Page 99: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

99

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)

Page 100: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

100

¿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.)

Page 101: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

101

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"

Page 102: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

102

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.*;

Page 103: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

103

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

Page 104: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

104

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;

Page 105: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

105

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

Page 106: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

106

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.

Page 107: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

107

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.

Page 108: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

108

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

Page 109: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

109

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;

Page 110: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

110

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

Page 111: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

111

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)

Page 112: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

112

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

Page 113: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

113

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

Page 114: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

114

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"

Page 115: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

115

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

Page 116: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

116

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"); } } }

Page 117: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

117

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

Page 118: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

118

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

Page 119: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

119

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

Page 120: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

120

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

Page 121: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

121

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"

Page 122: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

122

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)

Page 123: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

123

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

Page 124: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

124

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

Page 125: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

125

} 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

Page 126: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

126

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

Page 127: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

127

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

Page 128: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

128

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.

Page 129: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

129

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.

Page 130: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

130

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?

Page 131: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

131

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

Page 132: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

132

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.

Page 133: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

133

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)

Page 134: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

134

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

Page 135: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

135

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

Page 136: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

136

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

Page 137: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

137

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.

Page 138: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

138

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. }

Page 139: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

139

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"); } }

Page 140: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

140

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í”?

Page 141: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

141

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");

Page 142: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

142

} 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){

Page 143: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

143

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)

Page 144: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

144

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.

Page 145: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

145

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

Page 146: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

146

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

Page 147: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

147

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

Page 148: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

148

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.

Page 149: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

149

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

Page 150: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

150

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

Page 151: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

151

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

Page 152: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

152

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();

Page 153: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

153

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.

Page 154: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

154

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.

Page 155: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

155

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

Page 156: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

156

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

Page 157: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

157

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){} } }

Page 158: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

158

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

Page 159: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

159

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)

Page 160: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

160

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

Page 161: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

161

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.

Page 162: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

162

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

Page 163: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

163

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?

Page 164: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

164

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)

Page 165: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

165

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

Page 166: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

166

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

Page 167: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

167

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.

Page 168: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

168

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

Page 169: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

169

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

Page 170: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

170

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

Page 171: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

171

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

Page 172: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

172

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

Page 173: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

173

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;

Page 174: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

174

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

Page 175: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

175

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); } }

Page 176: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

176

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.*;

Page 177: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

177

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:

Page 178: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

178

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

Page 179: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

179

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

Page 180: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

180

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

Page 181: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

181

//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:

Page 182: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

182

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.

Page 183: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

183

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

Page 184: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

184

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?

Page 185: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

185

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

Page 186: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

186

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

Page 187: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

187

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

Page 188: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

188

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

Page 189: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

189

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.

Page 190: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

190

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

Page 191: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

191

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

Page 192: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

192

• 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) componentMoved(ComponentEvent) componentResized(ComponentEvent) componentShown(ComponentEvent)

addComponentListener()

ContainerListener componentAdded(ContainerEvent) componetRemoved(ContainerEvent)

addContainerListener()

FocusListener focusGained(FocusEvent) focusLost(FocusEvent)

addFocusListener()

ItemListener itemStateChanged(ItemEvent) addItemListener() KeyListener keyPressed(KeyEvent)

keyReleased(KeyEvent) keyTyped(KeyEvent)

addKeyListener()

MouseListener mouseClicked(MouseEvent) mouseEntered(MouseEvent) mouseExited(MouseEvent) mousePressed(MouseEvent) mouseReleased(MouseEvent)

addMouseListener()

MouseMotionListener mouseDragged(MouseEvent) mouseMoved(MouseEvent)

addMouseMotionListener()

TextListener textValueChanged(TextEvent) addTextListener() WindowListener windowActivated(WindowEvent)

windowClosed(WindowEvent) windowClosing(WindowEvent) windowDeactivated(WindowEvent) windowDeiconified(WindowEvent) windowIconified(WindowEvent) |windowOpened(WindowEvent)

addWindowListener()

Page 193: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

193

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.

Page 194: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

194

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.

Page 195: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

195

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

Page 196: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

196

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

Page 197: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

197

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)); } }

Page 198: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

198

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

Page 199: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

199

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

Page 200: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

200

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

Page 201: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

201

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.

Page 202: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

202

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

Page 203: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

203

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

Page 204: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

204

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?

Page 205: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

205

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

Page 206: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

206

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.

Page 207: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

207

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?

Page 208: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

208

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(){

Page 209: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

209

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.

Page 210: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

210

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

Page 211: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

211

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

Page 212: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

212

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)

Page 213: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

213

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

Page 214: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

214

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.

Page 215: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

215

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.

Page 216: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

216

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); }

Page 217: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

217

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

Page 218: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

218

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)

Page 219: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

219

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)

Page 220: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

220

¿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

Page 221: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

221

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

Page 222: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

222

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)

Page 223: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

223

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(

Page 224: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

224

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

Page 225: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

225

//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?

Page 226: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

226

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.

Page 227: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

227

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/

Page 228: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

228

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

Page 229: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

229

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

Page 230: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

230

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.

Page 231: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

231

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.

Page 232: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

232

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

Page 233: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

233

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

Page 234: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

234

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

Page 235: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

235

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{

Page 236: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

236

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.

Page 237: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

237

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

Page 238: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

238

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.

Page 239: Tutorial SCJP12

javaHispano. Tu comunidad, tu lenguaje.

239

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.

Page 240: Tutorial SCJP12

Tutorial para el examen de certificación: SCJP 1.2

240

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