K i m e r a w e b e m a i l : b r u j u l a t o @ y a h o o . e s m s n : k i m e r a @ k i m e r a w e b . e s f b : k i m e r a k i m e r a w e b 1 6 / 0 9 / 2 0 1 2 Kimeraweb Estas clases gratuitas pretenden abarcar los aspectos mnimos que hay que conocer para poder programar en cualquier lenguaje usando como herramienta el Lenguaje Java. Como modelo usar el emulador L2J. El curso est dirigido a todos los niveles de usuarios, desde los que no tienen conocimiento de programacin a los programadores habituales.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 1 El ndice se ir modificando conforme este manual se expanda. ndice Tema 1, Introduccin. 1.1 Conceptos de programacin orientada a objetos 1.2 Desarrollo de un objeto 1.3 El cuerpo de un objeto 1.4 Reglas para crear nombres (nomenclatura) Tema 2, las clases 2.1 Alcance de una clase 2.2 Reglas de declaracin de una clase 2.3 Creando una clase 2.4 La clase abstracta
Tema 3, los mtodos
3.1 Funciones de un mtodo 3.2 Modificadores de acceso 3.3 Modificadores que no dan acceso 3.4 Argumentos de los mtodos 3.4.1 Pasando variables referenciando a objetos 3.4.2 Pasando variables primitivas 3.5 Constructores
Tema 4, las variables
4.1 Variables primitivas 4.2 Variables de instancia 4.3 Variables locales 4.4 Variables de tipo final, transient y volatile 4.5 Variables estticas 4.6 Arrays 4.6.1 Inicializando los elementos en un bucle 4.6.2 Arrays annimos 4.6.3 Arrays primitivos 4.6.4 Array de referencias a objetos 4.6.5 Asignaciones para arrays de una sola dimensin 4.6.6 Asignaciones para arrays de varias dimensiones Tema 5, Enumeraciones 5.1 Declarando una enumeracin 5.2 Declarando mtodos y variables en una enumeracin
Tema 6, usando las caractersticas de la POO
6.1 La encapsulacin 6.2 Polimorfismo
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 2 6.3 Casteo de variables de referencia 6.4 Implementando una interfaz 6.5 Tipos de retornos en constructores sobrecargados 6.5.1 Devolviendo un valor 6.6 Autoboxing
Tema 7, los constructores
7.1 Construccin, reglas y sobrecargas de constructores 7.2 Encadenamiento de constructores
Tema 8, modificador esttico
8.1 Mtodos y variables estticas 8.2 Mtodos estticos y variables
Tema 9, recolector de basuras
9.1 Funcionamiento del recolector de basuras 9.1.2 Cmo funciona el recolector de basuras? 9.1.3 Puede una aplicacin Java quedarse sin memoria? 9.2 Escribir cdigo que maneje explcitamente objetos elegibles para ser borrados 9.3 Reasignado una variable de referencia 9.4 Aislando una referencia 9.5 Forzando el recolector de basuras 9.6 Limpiar antes de ejecutar el GC - el mtodo finalize() Tema 10, operadores 10.1 Operadores de asignacin 10.2 Operadores de asignacin compuestos 10.3 Operadores relacionales 10.4 Operaciones de igualdad 10.5 Comparacin de primitivos 10.6 Igualdad para variables de referencia 10.7 Igualdad para enumeraciones 10.8 Comparacin con instanceof() 10.8.1 Errores de compilacin con instanceof() 10.9 Operadores aritmticos 10.9.1 El operador resto % 10.9.2 Operador de concatenacin de cadenas 10.10 Operadores de incremento y decremento 10.11 Operador condicional 10.12 Operadores lgicos 10.13 Operadores e Bitwise 10.14 Atajo para operadores lgicos 10.15 Operadores lgicos sin atajos 10.16 Operadores lgicos ^ y
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 3 Tema 11, Control de flujo
11.1 Estamento if 11.2 Estamento switch 11.2.1 Expresiones vlidas para switch y case 11.2.2 Interrupciones y flujo en los boques switch 11.2.3 El caso default 11.3 Estamento while 11.4 Estamento do while 11.5 Estamento for, o for-in (el bucle bsico) 11.5.1 El for mejorado (para arrays, for each) 11.6 El uso de break y continue 11.6.1 Estamentos sin etiquetas 11.6.2 Estamento con etiquetas
Tema 12, excepciones y aserciones
12.1 El estamento try catch 12.1.1 El uso de finally 12.1.2 Programacin de excepciones no capturadas 12.1.3 Definiendo excepciones 12.1.4 Jerarqua de las excepciones 12.1.5 Manejando una clase completa de la jerarqua de excepciones 12.1.6 Declaracin de Excepciones e Interfaces Pblicas 12.1.7 Relanzando la misma excepcin 12.1.8 Definicin de conceptos, excepcin y error 12.1.9 Programando el arrojo de excepciones 12.2 Mecanismo de aserciones 12.2.1 Reglas de expresin de las aserciones 12.2.2 Aserciones, identificados o palabra clave 12.2.3 Ejecucin con aserciones 12.2.4 Selector para activar y desactivar los assert 12.2.5 El uso apropiado para las aserciones
Tema 13, la clase String, StringBuilder y StringBuffer
13.1 La clase String 13.1.1 String y memoria 13.1.2 Mtodos importantes de la clase String 13.2 StringBuffer y StringBuilder 13.2.1 Mtodos importantes de las clases StringBuffer y StringBuilder
Tema 14, paquete I/O, lectura y escritura de ficheros
14.1 Resumen de las clases I/O 14.2 Creando ficheros, el uso de la clase File 14.3 El uso de FileWriter y FileReader 14.4 Combinando clases I/O, BufferedWriter y BufferedReader 14.5 Ficheros y directorios
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 4 Tema 15, paquete I/O, la serializacin
15.1 ObjectOutputStream y ObjectInputStream 15.2 Objetos grficos 15.3 El uso de writeObject y readObject 15.4 La herencia y la serializacin 15.5 Serializacin y clases estticas
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 5 S que queremos hacer cosas ya, pero este manual no va indicado para personas con inquietudes exprs, es decir, lo leo ya y lo quiero ya. Un buen programador, espero que cuando acabes el manual lo seas, ha de ser meticuloso y usar todas las reglas aceptadas universalmente por los programadores, muy importante cuando se trabaja en equipo o se retoma el trabajo de otra persona, como es nuestro modelo L2J. En este captulo sabremos que es un objeto, como funciona y reglas de programacin. No te preocupes, empezaremos a programar tan pronto tengas la base necesaria. Acurdate de que un gigante con pies de barro...
1.1 Conceptos de la programacin orientada a objetos En programacin moderna, se usa una estructura llamada programacin orientada a objetos. Esto no es ms complicado que decir para programar algo haremos uso de otros cdigos que ya existen. Entonces, el concepto de objeto: ahora mismo diremos que un objeto es un programa que podemos incorporar a nuestro cdigo. En este objeto existen funciones. Una funcin, tal como su nombre indica es algo que est destinado a hacer, por ejemplo, las funciones de un coche? Frenar, acelerar, girar... Ahora imaginemos algo que podramos crear en breve, un formulario. Funciones de un formulario? Recoger informacin, guardar informacin, recuperar informacin... Que podra necesitar el formulario para guardar la informacin al disco? Acceso al disco, obviamente y... tendremos que crearnos un programa para poder grabar al disco? NO!! Afortunadamente, todos los lenguajes tienen incluidos objetos bsicos (realmente no son tan bsicos, se podran escribir miles de pginas... pero de momento lo dejamos aqu) que usaremos. Os habis dado cuenta de una cosa? Un objeto que slo sirve para acceder al disco... y nada ms.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 6 1.2 Desarrollo de un objeto Los objetos en cualquier lenguaje, y Java no es una excepcin, es que deben ser de bajo acoplamiento y alta cohesin. Bueno, y esto para qu sirve? Ojo, si no ejecutas esta premisa a la perfeccin, tu programa va a ser un churro (para que hablar con rodeos). Primero, entremos en detalles, que es bajo acoplamiento? Un programa de bajo acoplamiento significa, que si el programa se modifica, no afectar al objeto que lo usa. Por ejemplo, imaginemos que tenemos un objeto llamado SUMADOR que lo nico que hace es sumar dos nmeros. Este objeto se invoca por otro objeto llamado CALCULADORA. SUMADOR acepta tomar dos nmeros y devolver su suma. Por cualquier desdicha de la naturaleza, el cdigo de SUMADOR tiene que ser reescrito porque se ha descubierto un fallo en su programacin. El bajo acoplamiento significa que aun reescribiendo el cdigo de SUMADOR, CALCULADORA seguir usando a SUMADOR sin tener que editar su cdigo, resumiendo, SUMADOR es totalmente independiente de CALCULADORA. La alta cohesin significa que el programa har exactamente y nicamente eso para lo que fue diseado, y nada ms; de esta manera, sabemos que SUMADOR solo suma, y no har las funciones de RESTADOR (ms adelante explicaremos otras ventajas). Con lo explicado aqu, sera censurable que CALCULADORA fuese un objeto que hiciese otra tarea que no fuese calcular, y que su edicin forzase a que otro objeto que usase CALCULADORA tuviera que ser editado tambin.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 7 1.3 El cuerpo de un objeto Un objeto comn, est compuesto de funciones y variables. Explicado brevemente, el objeto tiene como misin hacer algo, y sus funciones son las tareas que puede realizar. Hay tareas que necesitan guardar alguna informacin para poder ser realizada, para guardar esta informacin se usan variables (porque su valor varia al menos, una vez). Entonces, resumiendo porque esto no tiene ms: Los objetos contienen funciones y contienen variables. Las funciones contienen variables. Al principio cit objeto comn porque ms adelante veremos otra clase de objetos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 8 1.4 Reglas para crear nombres, o nomenclatura. Como sabemos cundo leemos un cdigo, si lo que leemos es un objeto, una funcin o una variable? Es por su nomenclatura (no, no vamos a hacer qumica... todava). Las reglas para crear nombres son: Un objeto (tambin se le llama clase) siempre comienza su nombre por maysculas. Una funcin siempre comienza su nombre por minsculas. Una variable de clase ir antecedida con el smbolo de guin bajo _, ejemplo _xPos. Este tipo de variables suelen ser privadas. Las veremos ms adelante. Las dems variables sern en minsculas. Aparte de la nomenclatura, los nombres de las clases tienen que ser descriptivas, es decir, su nombre debe intuir lo que va a hacer, de tal manera, que cualquier lector ajeno al proyecto, pueda saber, sin leer el cdigo, que es o hace la clase. Sus mtodos deben ser creados de forma verbal, por ejemplo, las funciones de un coche se llamarn frenar, acelerar y no freno o aceleracion. Cuando se quiere obtener o asignar valores, se usan get y set, seguidos del nombre, get significa obtener, y set, seleccionar. As que si queremos obtener la velocidad del coche, getVelocidad. Si lo que deseamos es saber si una operacin se est realizando, usaremos is, que significa en castellano, ser o estar. Est frenando? -> isFrenando. Debo decir, que en ingls, queda mejor -> isStopping. Si estas fijndote, cuando se unen dos palabras, la segunda se pone en maysculas, a esto se le llama camelCase, y tambin es otra regla que se aplica a todo. Adems de las clases y funciones, las variables si van a trabajar durante un periodo largo, tambin han de ser descriptivas, por ejemplo, fuerzaDeFrenado = 100. Para terminar, las constantes de clase en maysculas, sin usar camelCase, y su lugar, guion bajo (constante es una variable que una vez asignado su valor, ya no va a cambiarlo) ejemplo: ANCHO_DOCUMENTO.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 9 2.1 Asignar el alcance de una clase Estos modificadores tambin se pueden aplicar a las funciones y variables. Cuando creas un objeto, puedes querer que ese objeto, pueda ser usado o no, dentro de su mbito. Podemos querer que nuestra clase CALCULADORA sea invisible para la clase INSTRUMENTO MUSICAL y que sea visible para la clase MATEMATICAS por razones evidentes.
Para poder hacer esto, al declarar una clase, podemos hacerlo de diferentes maneras: Public Al declarar una clase como pblica, ser visible desde cualquier otra clase situada en cualquier otra parte. Sin modificador o Default Por defecto, una clase es visible en el paquete que se crea nicamente.
Al igual que creamos directorios en Windows (u otro sistema operativo) para agrupar ficheros que son comunes entre s, o sea, que tienen alguna relacin entre ellos, los ficheros creados en Java tambin cumplen la misma lgica. En un paquete Musica podramos encontrar los paquetes Instrumento de Percusion, Instrumento de viento, Instrumento de cuerda, y dentro de cada uno, mas directorios. Cada directorio se denomina paquete.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 10 2.2 Reglas de declaracin de una clase Antes de crear tu primera clase, an tienes que conocer unas reglas ms, si, lo siento, es pesado pero necesario, pero no te preocupes, slo con leerlas, te acordars de ellas, porque a medida que avancemos, vers que son normas evidentes. Slo puede existir una clase pblica por fichero fuente. El nombre de la clase siempre ser el mismo que el nombre del fichero que la contiene. Si la clase est dentro de un paquete, el estamento package ser lo primero que aparezca en el fichero de la clase conteniendo su ruta. Lo siguiente que aparece despus de un package, son los comandos import. Las instrucciones import y package se aplican a todas las clases del fichero, en otras palabras, no hay manera de declarar diferentes package para cada clase definida en el fichero. Un fichero puede tener ms de una clase no pblica. Las clases no pblicas del fichero pueden tener un nombre distinto al fichero que las contiene.
En un package se inserta la ruta de la clase. Los import se usan para importar otras clases.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 11 2.3 Creando una clase Bien, ya hemos ledo todas las normas habidas y por haber para crear una clase. En estos momentos somos unos eruditos en lo que a normas se refiere pero ya vamos a empezar la accin. Nuestra primera clase va a hacer poco, ya que, como dije antes, la programacin orientada a objetos se basa en el uso de otras clases para hacer uso de ellas, y como no hemos visto ninguna, no podemos hacer nada. Est fue una gran leccin, verdad? Nunca la olvidars. Pero aun sin conocer ninguna clase, podemos crear un pseudo cdigo que tiene como misin introduciros en el mundo de la programacin orientada a objetos, POO. Mi primera ilustracin va a consistir en crear un coche y sus funcionalidades. public class Coche {
public void frenar() { } public void acelerar() { }
public String getAceleracion() {return null; } public String getFrenada() {return null; }
}
Que estamos viendo aqu? Primero, al escribir la clase, se indica su visibilidad. Recuerda que si no se indica, se obtiene un alcance por defecto, es decir, slo es visible en el paquete que se crea. Despus tenemos la instruccin class y el nombre de la clase abriendo y cerrando llaves al final del cdigo, encerrando sus mtodos. En sus mtodos podemos ver tres palabras que no habamos visto antes, se trata de void, String y return. Cuando un mtodo no devuelve nada, al nombre del mtodo le precede la instruccin void. Cuando un mtodo devuelve algo, le precede el nombre del tipo que devuelve y entre corchetes la instruccin return seguido de una variable (en este caso, nada, null). El tipo se refiere a la clase de objeto que va a ser devuelto. Clases de tipos son por ejemplo, cadenas (conjunto de letras), nmeros, nombres de clases como String, Integer, Object, etc...
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 12 2.4 La clase abstracta El nico propsito de una clase abstracta es la de crear un patrn para crear clases del mismo tipo y funcionalidad que la clase abstracta. No puede duplicarse. abstract class Coche { private double precio; private String modelo; private String year; public abstract void goFast(); public abstract void goUpHill(); public abstract void impresionarVecinos(); }
Cuando creas un coche heredando la clase abstracta Coche, lo que haces es coger un patrn y asimilarlo a tu cdigo. Podras pensar que, qu utilidad tiene esto? Imagina que eres el programador de Coche, y has creado un programa que usa los mtodos creados en Coche. Otro programador, podra crear un Coche como el tuyo, que adems volase, pero para que el cdigo ya implementado por ti funcione correctamente en el coche volador, necesita implementar los mtodos que tu esperas que estn ah, como el precio, el modelo, el impresionarVecinos... aparte este nuevo programador, hara que su coche volase sin tener que programar el precio, el modelo, el goFast... que ya estn creados por ti. Extrapola esto a un NPC de Lineage, si tienes un NPCWalker que quisieras a la vez que vendiera como un GMShop, que necesitas? Un NPCWalker vendedor, cierto? Al implementar esto en tu nuevo coche, inmediatamente se incluirn los cdigos necesarios para que tu clase est correctamente implementada.
Si te fijas, en cuanto heredo CochePlantilla, me exige Add unimplemented methods, aadir mtodos no implementados. En cuanto pulses ah, se implementarn los mtodos, pero el cdigo de su interior, es cosa tuya.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 13 Los mtodos marcados como abstractos terminan siempre en punto y coma, en lugar de llaves. Si el mtodo estuviera en una clase normal, es decir, con cdigo, con tan slo un mtodo abstracto que tenga una clase, tiene que ser marcada como abstracta tambin. Cuando una clase abstracta, lo es al 100%, es decir, que no posee ningn cdigo, algo como esto:
se dice que es una interfaz. Mientras que en una clase abstracta puedes tener funciones con cdigo y funciones abstractas mezcladas, en una interfaz no. Tambin, los mtodos de una interfaz son por defecto pblicos y abstractos, por lo tanto no tienes que declarar que son pblicos y abstractos. La razn es simple, si el mtodo fuera privado, cuando heredases la clase abstracta, las subclases no tendran acceso a ellos.
En la interfaz, las variables que puedes crear tienen que ser pblicas (por lo explicado antes), estticas (que no cambian su valor) y finales (que no pueden duplicarse). Sin embargo, los mtodos no deben ser estticos, ya que, cuando se hereda la interfaz, los mtodos abstractos hay que editarlos. Si fueran estticos, no se podran modificar. Una interfaz puede heredar una o ms interfaces, adems, no puede heredar otra cosa que no sea una interfaz. No confundir heredar con implementar, ya que la interfaz no puede implementar nada. Cuando se declara una interface, debe ser indicado con el modificador interface.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 14 Si quieres que tu interfaz sea accesible desde cualquier parte del cdigo, has de aadir el modificador public, sino el acceso por defecto (de paquete, default) ser seleccionado.
Aunque sea redundante, puedes usar los modificadores public y abstract para declarar una interfaz.
En una interface, como dije antes, puedes declarar constantes. Al hacer esto, se garantiza el acceso a esa variable desde cualquier clase.
Los modificadores que tienes que usar son: public static final, es decir, que son pblicas, que no varan su valor, y que no se pueden duplicar. Al no poder duplicarse, te aseguras que ninguna clase tenga acceso a la variable y altere su valor.
Si en cualquier caso olvidases esto, no olvides que, aunque no declares la variable como tal, ser tomada como public static final irremediablemente:
por lo tanto, al querer modificar la variable:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 15
obtenemos un error que nos comunica que borremos el modificador final de VELOCIDAD_MAXIMA, y como veis en la captura anterior, no existe tal modificador, es decir, se hace evidente que JDK nos ha declarado por defecto que es public, static y final.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 16 3.1 Funciones de los mtodos. Sin los mtodos, las clases no tendran mucho sentido. Los mtodos son los responsables de que la clase cobre vida, y sentido. Cuando invocamos una clase, actuamos sobre sus mtodos. Lo principal que definimos en un mtodo, son las funciones get y set, encargadas de devolver y actuar sobre las variables de la clase directamente. Es una buena prctica crear las variables de las clases de forma privada, y manipularlas a travs de sus mtodos para evitar fallos en su uso. Por ejemplo, podramos usar la clase Coche, y en su variable VELOCIDAD_MAXIMA, le passemos un valor de cadena en lugar de un valor numrico, tal como se esperaba. Sin duda, acabara en tragedia:
Para evitar situaciones parecidas, la buena prctica nos obliga a usar un mtodo para prevenir o evitar errores, porque, en lugar de una cadena de texto, podramos haber pasado como valor un nmero decimal, pero aun as, sera un valor incorrecto. Las funciones pueden ejecutar una serie de acciones y devolver un valor, o no devolver nada. Para indicar que no devuelve nada, despus del modificador, o antes del nombre de la funcin, indicamos con void nuestra intencin, que traducido significa vaco, es decir, devuelve un valor vaco. Cuando queremos devolver el resultado de una operacin, de cualquier clase, entonces el lugar de void lo ocupa el tipo de objeto que vamos a devolver, una cadena (String), un objeto (Object) u cualquier otra cosa que hayamos inventado (un Coche por ejemplo). Para usar el mtodo de una clase, se usa el nombre de la clase seguido por un punto, y luego el nombre del mtodo. Es como el ejemplo, solo que, una funcin lleva parntesis, y las variables no llevan.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 17 3.2 Modificadores de acceso Los modificadores de acceso de los mtodos son cuatro, en lugar de dos como en las clases (Default y Public) y sus caractersticas son compartidas con las variables. Si no defines ningn modificador, el modificador por defecto es Default (te lo recuerdo nuevamente, con Default solo se logra visibilidad dentro del paquete donde se crea). Public Cuando un mtodo o una variable se declara pblica puede verse desde cualquier parte del programa. Private Cuando el mtodo o la variable se declara privada, solo es accesible donde es creada. Protected Igual que privada, slo que tambin ser accesible por sus subclases. Default Por defecto, no estas forzado a declarar una clase Default. Si se omite el modificador, Default es tomado por defecto.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 18 3.3 Modificadores que no dan acceso. Estos modificadores se usan para limitar el uso de los mtodos, se les denominan Nonaccess y hay siete clases.
Final Se usa para evitar que el mtodo sea sobrescrito en una subclase. Si se pasa final como parmetro al mtodo, es decir, proporcionarle un valor final, el mtodo no podr cambiar el valor.
Abstract Un mtodo abstracto se declara pero no se implementa. En otras palabras, es un mtodo no funcional. Recuerda que un mtodo abstracto no lleva llaves, termina en punto y coma. Cuando usas este modificador, lo que buscas es que la subclase implemente estos mtodos, forzando a definir las acciones que debe hacer la clase, pero no la manera en que debe hacerlas. As por ejemplo, nuestro Coche puede obligar a sus subclases a implementar gastarCombustible, y dependiendo del coche, podra gastar gasolina, diesel, queroseno, agua, hidrogeno...
Ahora una pregunta de control antes de continuar, podras crear un mtodo abstracto y final? Piensa en ello, la respuesta ms adelante.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 19 Synchronized Indica que el mtodo slo puede ser accedido una vez al tiempo, es decir, que hasta que la tarea con la primera clase que invoc este mtodo no haya acabado, pondr en espera a los dems hilos que estn esperando ejecutar este hilo. Esto es til para una tarea como guardar un fichero. Si se estn guardando datos, sera un error permitir que otro hilo insertase nuevos datos mientras se lleva a cabo la operacin de salvar datos. El resultado final es imprevisible. Las variables no pueden ser declaradas Synchronized.
Native Este modificador indica que el mtodo se ha implementado desde otra plataforma de cdigo diferente, normalmente en lenguaje C. Tambin, al igual que Synchronized, es exclusivo de los mtodos.
Transient Para entender este, hay que saber primero que es serializar. Cuando se serializa un objeto, se pretende guardar la informacin que contiene normalmente en disco. Por ejemplo, el objeto Agenda podra contener objetos Personas. Si queremos guardar el contenido de la agenda, primero, hay que serializar el objeto. Bien, pues Transient indica que ese campo no debe ser serializado por ejemplo, porque sean derivadas de otros campos.
Strictfp Se usa para asegurar que cualquiera que sea la plataforma donde se ejecute el programa, la precisin de un nmero decimal sea el mismo. Si se omite, la JVM usar la precisin que mejor considere.
Static El ms complejo de usar. Resumir brevemente aunque ser comentado en profundidad ms adelante. Una variable esttica es una variable que pertenece a la clase, no al objeto, quiero decir, una instancia de ese objeto (una instancia, un clon). Las variables estticas se inicializan una sola vez, al comienzo de la ejecucin del programa antes que cualquier otra variable. Un mtodo esttico slo puede acceder a otros mtodos estticos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 20 Un mtodo o variable esttica es accesible directamente, NombreClase.NombreMetodo. Un mtodo esttico no puede usar this o super. Se puede marcar como static: Mtodos Variables Clases anidadas (no dentro de un mtodo, se ver ms adelante) Inicializacin de bloques No se puede marcar como static: Constructores (ya que se usan para crear instancias) Clases (a menos que estn anidadas) Interfaces Mtodos locales dentro de las clases (lo veremos en detalle) Mtodos internos de clase y variables de instancia. Variables locales.
La palabra reservada this se usa para referirse a la variable de la clase, y super a la variable de la superclase, es decir, la clase de la que se deriva la clase actual.
La respuesta a la pregunta, se puede declarar un mtodo como abstracto y final es... falso. Ambas declaraciones son opuestas, un mtodo abstracto tiene que ser sobrescrito, recuerda que se declara sin cdigo, mientras que un mtodo final evita ser modificado.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 21 3.4 Argumento de los mtodos Es comn en cualquier lenguaje, que los mtodos acepten parmetros, es decir, en un objeto, para que se cree una accin, a veces es necesario decirle alguna informacin. Por ejemplo, si el mtodo fuera, acelerar, una pregunta obvia sera, cunto? Recordarte antes que nada, que un mtodo se crea primero poniendo su modificador de acceso (que es opcional, sino se elige, la JVM toma Default), luego el tipo de retorno que poda ser cualquier cosa (si no quieres ningn tipo de retorno, se escribe void), seguido del nombre del mtodo y entre parntesis los parmetros. Pues en Java, la manera ms simple de crear un mtodo es hacer uno que no tome ningn parmetro: public class ejemplos {
public void digoHola() { System.out.print ("HOLA"); }
}
Explico un poco lo que vemos, primero, la clase, que abre llaves y encierra a un mtodo que no toma parmetros y se cierran las llaves de la clase. En el interior de la clase, el mtodo se declara encerrando entre llaves las acciones. Cuando insertamos un parmetro en el mtodo, debemos decirle a la JVM el tipo de dato que va a ser insertado. Puede ser cualquier cosa que exista. En este ejemplo, ser de tipo String, que significa cadena de texto. public class ejemplos {
Ahora podemos ver que al ejecutar nuestro ejemplo, nos pedir un nombre para incluir, y que en el mtodo usaremos ese nombre para incluir en el saludo.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 22 Continuemos con el ejercicio y ahora tomaremos la edad como siguiente parmetro: public class ejemplos {
public void digoHola(String nombre, String edad) { System.out.print ("HOLA " + nombre + ", se que tienes " + edad + "aos."); }
}
Ahora nuestro resultado sera algo como: Hola Maria, se que tienes 17 aos. El cdigo para obtener este resultado sera: ejemplos.digoHola("Maria","17);
Puedes seguir sumando parmetros hasta que la RAM de tu ordenador se quede sin memoria. No hay problema. Si quisiramos hacer una operacin matemtica con la edad, usaramos el tipo int, que significa, entero, o mejor dicho, nmero entero:
La clase main, que sera la clase que siempre se ejecuta primero por defecto y porque la JVM busca un mtodo llamado main para ejecutar el programa. Sino existiese ningn mtodo main, nos lanzara un error.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 23 La consola nos devuelve el resultado de la operacin.
Como colofn de los parmetros hay un argumento denominado var-args, cuando declaramos como parmetro un var-args estamos diciendo que esperamos un nmero indeterminado de parmetros. Este tipo slo se acepta una sola vez en un mtodo y siempre tiene que ser declarado el ltimo:
Salida de la consola:
Esta forma var args se forma escribiendo tres puntos despus del tipo y en realidad lo que hace es convertir la variable en un array que se puede recorrer con un for.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 24 Conceptos nuevos: Un array es una variable capaz de almacenar ms de un dato. Este for se denomina foreach porque toma un valor del array y lo introduce en una variable. Se trata de un bucle que recorre todos los valores almacenados en la variable, en cada vuelta introduce el valor del array en la variable hasta llegar al ltimo valor. Un bucle es un bloque de instrucciones que se repite un nmero de veces.
Todo esto se ver ms en detalle.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 25 3.4.1 Pasando variables referenciando a objetos La memoria en Java se divide en 2 partes, la memoria permanente, Heap, donde viven los objetos, y la memoria Stack, donde viven las variables. Cuando pasas un objeto como argumento a un mtodo, debes tener en cuenta que ests pasando un objeto de referencia, y no el objeto en s mismo. Recuerda que una variable de referencia almacena los bits que representa (para la JVM) una manera de conseguir ese objeto en la memoria Heap. Ms importante, tienes que recordar que no ests pasando la variable de referencia actual, sino una copia. Una copia significa que consigues el patrn de bits de la variable de referencia, as que cuando pasas una variable de referencia, estas pasando la copia de bits del objeto que representa. En otras palabras, ambos, el invocador y el mtodo invocado tendrn ahora una copia idntica de la referencia, pero ambos se refieren exactamente al mismo objeto del Heap (no a la copia).
3.4.2 Pasando variables primitivas Cuando una variable primitiva se pasa por un mtodo tampoco cambia de valor, ya que se pasa una copia de la variable, al igual que ocurre con los objetos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 26 3.5 Constructores En un lenguaje orientado a objetos la principal caracterstica es que los objetos se instancian para obtener nuevos objetos con distinto comportamiento. Por ejemplo, si creamos un objeto Coche, las propiedades del objeto podran ser, marca, modelo, potencia y velocidad mxima por poner un ejemplo. Si a cada modelo Coche, le asignamos una marca distinta, estamos creando nuevos modelos de coches, al fin y al cabo son coches con distintas caractersticas. No creamos un modelo Ford, otro Ferrari y otro modelo Porche, sino que creamos estos modelos a partir de un objeto que rene todas las similitudes de un Coche. Habiendo aclarado que instanciando un objeto Coche podemos crear nuevos coches con distintos comportamiento, es hora de explicar la funcin de un constructor. Cada vez que instancias un objeto, por decirlo de otra manera, un nuevo clon de un objeto, ests ejecutando un constructor. Si no lo haces t, la JVM lo hace por ti. La primera cosa que llama la atencin es que un constructor se parece horrores a un mtodo, y para diferenciar un mtodo de un constructor nos fijamos que el constructor no lleva return ni lleva void.
Qu vemos aqu? Pues estamos viendo dos clases, la clase pblica Main creando un Ferrari, y la clase por defecto Coche. Recuerda que un fichero slo puede tener una clase pblica. Para instanciar un objeto se usa el comando new. Para convertir la variable Ferrari en una instancia de coche, primero se usa el nombre del objeto que se va a instanciar, en el ejemplo es Coche, seguido de la variable, y luego usando new (traducido significa nuevo, nuevo Coche) seguido del objeto que queremos instanciar (o clonar, como lo veas ms claro) y entre parntesis, las opciones del constructor. Si el constructor no existiese, la JVM implementara (aunque no aparecer en el cdigo): public Coche (){}
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 27 Ahora veamos el cdigo del Coche:
La variable de la clase, tal como indicamos antes, por el convenio de Java, se escribe en maysculas y los espacios separados mediante guin bajo, MARCA_DEL_COCHE. Luego tenemos el constructor, el nombre es el mismo que el de la clase, Coche, y su funcin es la de asignar la variable de la clase la marca del coche, de esta manera, cada vez que instanciemos un Coche, tendremos una marca. Luego tenemos un mtodo coche, respetando el convenio de Java para los mtodos, el formato del nombre es camelCase. Pero aun respetando el convenio, es una mala prctica nombrar un mtodo con el mismo nombre que su clase, porque slo es til para crear confusin, como es este caso. La funcin de este mtodo es imprimir en pantalla la marca del coche pasada por parmetro. Hay una tcnica de programacin que se llama sobrecarga de mtodos, consiste en crear mtodos con el mismo nombre pero aceptando diferentes parmetros.
Por ejemplo, aqu declaro dos constructores, el primer constructor (lnea 13) construye un coche sin parmetros, en la lnea 14 construye un Coche con la MARCA_DEL_COCHE.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 28 Ahora completemos lo que sera un Coche:
Este cdigo es algo ms completo definiendo el Coche. En la clase Coche ahora hay cuatro propiedades en lugar de una. Tambin tenemos un constructor que toma dos parmetros de tipo String (cadena de texto) y dos ms de tipo int (nmeros enteros). Para completar, aadimos un mtodo para obtener la informacin del Coche, respetando siempre el convenio de Java, usamos get como parte del nombre (traducido significa obtener). Ahora, al instanciar un Coche, tendremos que introducir toda la informacin que el constructor de la clase est esperando, sino, nos dar error y no nos dejar compilar. As que la clase pblica Main instancia un Coche pasando cuatro parmetros en lugar de dos. Si te fijas, los parmetros que no son cadenas de texto, se pasan sin usar comillas. Slo las cadenas de texto se rodean con comillas.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 29 Ahora hagamos dos coches y probemos el resultado.
La consola arroja:
la especificacin de los dos coches. Como ves, el usar un objeto con diferentes propiedades da como resultado nuevos objetos con diferentes comportamientos. Esto es la programacin orientada a objetos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 30 4 Las variables Decamos antes que las variables son palabras que guardan un valor, y el nombre de la variable debe ser significativo, para relacionar de forma humana lo que guarda.
4.1 Variables primitivas Hay ocho tipos de datos primitivos en Java, son: char: es un carcter, su rango va desde el 0 al 65,535 boolean: es un 0 o un 1, se usa para indicar si una condicin es falsa o verdadera. byte: almacena un valor entre -128 al 127. short: almacena un valor entre -32,768 y 32,767. int: almacena un valor entre -2,147,483,648 y 2,147,483,647. long: almacena un valor entre -9,223,372,036,854,775,808 y 9,223,372,036,854,775,807 float: almacena un valor entre 1.40129846432481707e-45 y 3.40282346638528860e+38 double: almacena un valor entre 4.94065645841246544e-324d y 1.79769313486231570e+308d Aunque para nuestros efectos, usaremos normalmente float. Esto slo es a ttulo informativo, no tendrs que aprendrtelo de memoria, aunque si tendrs que aprender bien boolean e int, que son los ms usados. Si prefieres aprendrtelo de otra manera, a m me gusta ms esta:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 31 4.2 Variables de instancia Las variables de una instancia (no de una clase), se definen dentro de una clase pero fuera de cualquier mtodo, y se inicializan cuando se inicializa la clase. Qu diferencia hay entre una variable de clase y otra de instancia? La variable de clase no se instancia, es decir, no se puede clonar con new. Muy importante es recordar que las variables de instancia pueden usar cualquiera de los cuatro niveles de acceso (te acuerdas? public, private, default y protected) y que pueden ser marcadas como final y transient. No puedes declararlas como abstract, synchronized, stricfp, native y por supuesto, static. Para entender variable de clase y variable de instancia, he modificado el cdigo:
Fjate que en la variable de instancia, cada modelo de Coche tiene sus propias caractersticas, pero al poner como esttica una de las variables, automticamente se transforma en variable de clase, y al asignarle un valor al Ferrari, tambin se le asigna el valor al Toyota, de manera que cuando se ejecuta:
Obtenemos:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 32 4.3 Variables locales Las variables locales se encuentran en los mtodos, viven y mueren dentro de el, y se destruyen cuando el mtodo ha terminado su tarea. Las variables locales slo pueden ser marcadas como final. Al contrario que las variables de clase, las variables locales para poder usarlas, es necesario inicializarlas primero, es decir, asignarle un valor. Que es declarar una variable? Decir que existe sin que contenga un valor, por ejemplo:
Que es inicializar una variable? Asignarle un valor (aunque sea un valor vaco).
Tambin puedes inicializar la variable cuando la declaras:
El resumen de los modificadores que puedes usar:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 33 4.4 Variables de tipo final, transient y volatile El modificador final hace imposible reiniciar la variable una vez que se ha obtenido un valor explcito (que es distinto que un valor por defecto, como ocurre con las variables de clase). Acurdate que una clase final no puede heredarse, un mtodo final no puede sobrescribirse en una subclase y una variable final, no puede modificar su valor. El modificador transient sirve para decirle a la JVM que ignore la variable cuando se quiere serializar el objeto o deserializarlo. Cuando de/serializas un objeto lo que haces es recuperar/almacenar la informacin (del/en disco duro por ejemplo). Este recurso tan interesante ser visto ms adelante en profundidad. El modificador volatile le dice a la JVM que el hilo que accede a la variable debe obtener su propia copia. Esto se usa en procesos multihilos, donde cada hilo de ejecucin podr variar el valor de la variable. Profundizaremos en esto ms adelante, ahora solo tienes que saber que existe para ser usados en programacin multihilos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 34 4.5 Variables estticas. El modificador static se usa para crear variables estticas. Una variable esttica pertenece siempre a la clase donde se crea, no a sus instancias (o clones). Como vimos en el ejemplo anterior, al crear una variable esttica en la clase Coche, su valor cambiaba en todas las instancias creadas con Coche, en el ejemplo, al cambiar el valor en Ferrari, Toyota tambin fue afectado.
4.6 Arrays Los arrays son variables de tipo objeto porque son capaces de guardar mltiples valores o variables al mismo tiempo. Pueden almacenar datos primitivos o referencias a objetos. Esta clase de variables viven en el Heap. Los arrays se declaran comenzando por el tipo de elemento que el array va a almacenar, puede ser un objeto o datos primitivos seguidos de llaves cuadradas, luego le seguira el nombre de la variable. Aunque podramos poner los corchetes al final, resulta menos legible. Si colocamos ms corchetes, estamos creando dimensiones.
Podemos hacer cosas absurdas como esta, aunque tambin son vlidas:
Esto es lo mismo que poner dos corchetes juntos. En la declaracin nunca se pone el tamao al contrario que ocurre con otros lenguajes, que se puede iniciar el array declarando la cantidad de slots disponibles en el array. Quiero decir, esto, es ilegal:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 35 La forma ms directa de construir un array es usando new seguido del tipo del array.
En este ejemplo hemos creado 11 slots para guardar cadenas de texto en la variable nombre. Digo 11 porque se cuenta a partir del cero, si contamos el cero y el diez, tenemos once slots. Cuando se inicializa una variable, por defecto, en los slots encontraremos los valores por defecto del objeto. Para una cadena es nada, para un nmero es cero, y para objetos es null. Null no significa que nulo, no es un error, como en otros lenguajes, significa que no guarda ninguna referencia a ningn objeto. En los arrays dimensionales podramos decir que son arrays de arrays (en caso de arrays de dos dimensiones), es como imaginar el juego de hundir la flota. Si declaras una variable de 10 y 10, imagnate un eje X de 10 posiciones y un eje Y de 10 posiciones (10 x 10), son 100 posiciones de memoria reservadas. Los arrays de dos dimensiones pueden ser declarados de las siguientes maneras:
Es decir, puedes inicializar la cantidad de slots en cada dimensin del array.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 36 4.6.1 Inicializando los elementos en un bucle Un bucle es un bloque de instrucciones que se repite mientras se cumple una condicin. Veremos las diferentes clases que hay en profundidad. Los objetos de un array tienen solo una variable pblica que devuelve el nmero de elementos del array. El ltimo valor del ndex es siempre uno menos que la longitud del array. Esto se debe a que la posicin cero del array se cuenta en la longitud. As que, array[3] es array.lenght = 4, suponiendo que haya un elemento en cada slot del array. La forma ms sencilla de recorrer un array es usar el for de tipo foreach (sera la forma que correspondera a otros lenguajes, en Java no hay distincin).
Lo que vemos aqu es que se ha declarado un array llamado numeros con 11 slots. El bucle es for y encierra entre llaves la repeticin de instrucciones. Dentro de for se declara a para que acepte cada elemento guardado en numeros. Inicializamos cada slot con el valor guardado en slot, que en cada repeticin del bucle suma uno (slot++). As que en cada bucle, se est eligiendo un slot para asignarle un valor (numeros[slot]=slot).
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 37 O sea, esto est haciendo: numeros[0] = 0 numeros[1] = 1 numeros[2] = 2 etc, hasta llegar al ltimo slot del array, el 9. Recuerda, del 0 al 9 son 10 slots. Otra manera es usando la antigua versin de for y la variable len del array.
Lo que estamos viendo aqu es que en el for se inicializa la variable x con el valor de cero. En segundo lugar se especifica la condicin que mientras sea cierta, ejecutar el bloque de instrucciones, esta es que x sea menor que la longitud de numeros. Finalmente, le sumamos a la variable x un uno. Dentro del bucle se iguala la variable numeros con el ndice x al valor de x. Es exactamente el mismo proceso que el anterior, slo que aqu el final del array lo conocemos porque hacemos uso de la propiedad length del array. En for actualizado, esto se hace de forma automtica, el bucle se detiene porque conoce el ltimo elemento. Otra manera de declarar e inicializar un array es asignarle los valores en la misma lnea:
Al hacer eso, ya le hemos dicho al compilador que nuestro array tendr 10 elementos. Se pueden crear los elementos in situ:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 38 4.6.2 Arrays annimos La otra manera de crear e inicializar un array se la conoce como array annimo. Esto sirve para crear un array justo en el momento de su uso, por ejemplo, para drselo a un mtodo que lo coja como parmetro. El array se crea sin variable de referencia.
4.6.3 Arrays primitivos Los arrays primitivos pueden aceptar cualquier valor que pueda ser promocionado implcitamente al tipo declarado en el array. Por ejemplo, un array de int, puede almacenar cualquier tipo de datos que pueda albergarse en 32bits. As que el siguiente cdigo es vlido:
4.6.4 Array de referencias a objetos Si el tipo de array es una clase, puedes poner objetos de cualquier subclase del tipo declarado en el array. Por ejemplo, si Subaro es subclase de Coche, puedes ponerlo tal como se muestra en el ejemplo:
Esto ayuda a recordar que los elementos en un Coche son solo variables de referencia a Coche. As que cualquier cosa que pueda ser asignada a Coche, puede ser asignada a un array de elementos de tipo Coche.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 39 Si el array es declarado como un tipo de interfaz, los elementos del array pueden referirse a cualquier instancia de cualquier clase que implemente la interfaz. El siguiente cdigo demuestra el uso de una interfaz en un array:
4.6.5 Asignaciones para arrays de una sola dimensin No estamos hablando sobre referencias en el array (en otras palabras, array de elementos), sino ms bien una referencia al array. Por ejemplo, si declaras un array int, la variable de referencia que declaras puede ser reasignada a cualquier array int (de cualquier tamao), pero no puede ser reasignado a cualquier que no sea un array int, incluyendo el valor int. Recuerda que todos los arrays son objetos, as que una referencia a un int no puede referirse a un nmero int. El siguiente cdigo muestra asignaciones vlidas y no vlidas para arrays primitivos:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 40 Es tentador suponer que porque una variable de tipo byte, short, o char puede ser explcitamente casteada y asignada a un int, un array de cualquiera de los tipos podra ser asignado a un array int. No puedes hacer eso en Java. Los arrays que almacenan referencias a objetos, lo opuesto a datos primitivos, no tienen restriccin. As como puedes poner un Honda en Coche (porque Honda hereda Coche), puedes asignar un array de tipo Honda a una variable de referencia tal como sigue:
Aplica el test ES-UN para distinguir lo que se puede de lo que no se puede hacer. Honda ES-UN Coche, as que el array de Honda puede ser asignado al array Car. Beer ES-UN Coche, no es cierto, no hereda Coche, as que no es vlido. Las reglas de los arrays se aplican por igual a las interfaces como a las subclases. Un array de interfaces, puede referenciar un array del tipo que haya implementado la interfaz. Recuerda que cualquier objeto de una clase que implementa una interfaz particular pasara el test de ES- UN. Por ejemplo, si Box implementa Foldable, lo siguiente, es vlido:
4.6.6 Asignaciones para arrays de varias dimensiones Cuando asignas un array a un array ya declarado, el array que asignas debe ser de las mismas dimensiones que las referencias que estas asignando. Por ejemplo, un array de dos dimensiones de int no se le puede asignar a un int normal, tal como sigue:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 41 Presta una atencin en especial a la asignacin de los arrays usando dimensiones diferentes. Podras por ejemplo, confundirte al asignar un array int al primero elemento de un array de int, como sigue:
Puedes inicializar los bloques que quieras en una clase. Lo importante a tener en cuenta, es que, al contrario que los mtodos o constructores, el orden en el que los bloques aparecen en la clase, si importa. Cuando es la hora en que tienen que ejecutarse los bloques, si la clase tiene ms de uno, empezaran a ejecutarse en el orden en que aparecen la clase... en otras palabras, desde arriba hacia abajo. Acurdate de estas reglas: Los constructores se ejecutan en el orden en que aparecen. Los bloques estticos solo se ejecutan una vez, cuando la primera clase se haya cargado. Las instancias de los constructores se ejecutan cada vez que la clase se instancia. Las instancia de los constructores se ejecutan despus de la llamada a super().
Este cdigo:
tendr esta salida:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 42 Como puedes ver, las instancias de los bloques init se han ejecutado dos veces. Instanciar los bloques init son a menudo usadas en lugar de poner todo el cdigo en los constructores en la clase que deberan compartir. De esa manera, el cdigo no tiene que estar duplicado a travs de los constructores. Finalmente, si haces un error en tu bloque esttico, la JVM puede arrojar un ExceptionInInitalizationError. Veamos un ejemplo:
producira un error como:
Los bloques estticos se ejecutan antes, sin importar si estn despus:
Este cdigo dar como resultado:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 43 5.1 Declaracin de una enumeracin Una enumeracin se usa para minimizar an ms los riesgos de equivocacin en un grupo de trabajo. Esta es una buena prctica, adems que facilita la lectura del cdigo. En Java se puede restringir una variable para tener unos valores predefinidos, a esto se le llama lista enumerada o enumeraciones. Digamos por ejemplo que tenemos varios tipos de coches que podemos tener, deportivos, turismo y comerciales. Para evitar que otro programador intente obtener un coche que no existe, digamos 4x4, se restringe los valores de la enumeracin a los que tengas creados. Declarar una enumeracin es tan fcil como esto:
Respetando el convenio de Java, se presentan en maysculas. El uso es igual de sencillo, adems, cuando declaras una enumeracin, el editor (yo uso Eclipse) te ayuda mostrando las opciones disponibles:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 44 De tal manera que la nica forma de conseguir coches ahora es usar las opciones que nos deja disponible la enumeracin:
Los componentes bsicos de una enumeracin son sus constantes. Pueden ser declaradas como clase propia (como en este ejemplo), miembro de una clase, pero no pueden ser declaradas dentro de un mtodo. As se declara como miembro de una clase:
Acurdate que slo puede existir una clase pblica por fichero. Esto sera miembro de una clase:
Es posible que encuentres la declaracin de una enumeracin terminando en ; esto es opcional.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 45 Bueno, y una vez que tengo una enumeracin, que hago? Antes hay que explicar un poco ms. Una enumeracin no es un tipo String o int. Cada miembro de una enumeracin es una instancia de la misma (o sea, un nuevo clon). As que DEPORTIVO no es slo una constante de la enumeracin, es un tipo de TiposDeCoches. Es decir, al igual que un tipo es un String o un int, pues acabamos de crear tres tipos nuevos de TiposDeCoches. Una enumeracin es como una clase, la diferencia es que a cada valor le corresponde una instancia de la enumeracin, donde la instancia es esttica y final, es decir, no se puede editar su valor, ni se puede hacer una subclase de ella (usar la palabra new) as que realmente se tratan como de una constante. A cada valor de la enumeracin le corresponde un orden de indexado, es decir, la enumeracin sabe en que orden estn los tipos de coche. Ms adelante profundizaremos en este tema, de momento tienes que saber que existe y cmo funciona bsicamente.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 46 5.2 Mtodos y variables en una enumeracin Una enumeracin adems de declarar tipos estticos y finales, puede ejecutar acciones al igual que una clase, es decir, podemos usar mtodos y variables, y algo raramente conocido como cuerpo de clase constante especfica. Esto es til por ejemplo, si quieres aadir una propiedad a los tipos, como por ejemplo, el nmero de puertas (por decir algo):
Bien, no te asustes, es sencillo y te lo voy a explicar. A cada tipo le hemos asignado un nmero, presumiendo que representan el nmero de puertas de cada tipo de coche. Pero para poder usar estos nmeros es necesario crear un constructor, ese constructor, al igual que en las clases, tiene el mismo nombre que la clase donde se crea. En nuestro caso acepta un parmetro de tipo int que se recoge del valor guardado en el tipo, es decir, nuestro constructor acepta un nmero que representa la cantidad de puertas del tipo de coche. Al igual que las clases, he incluido un mtodo para saber cuntas puertas tiene ese vehculo, getPuertas. No puedes olvidar que en el constructor no se puede invocar directamente. Se convoca automticamente con los argumentos que defines en las constantes. Por ejemplo DEPORTIVO(3) invoca al constructor y le pasa el parmetro 3. Esto lo habrs adivinado, y si no es as, es que necesitas practicar esto un poco. Coge Eclipse (u otro editor) y practica un poco. Al igual que en las clases, puedes sobrecargar el constructor, es decir, crear ms de uno. Tambin puedes hacer cosas extraas, como que parezca una clase annima interna (este tipo de clases la veremos ms adelante), se conoce como cuerpo de constante especfico y se usa cuando necesitas una constante para definir un mtodo definido en la enumeracin. Lo veremos ms claro con un ejemplo.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 47 Imaginemos que necesitamos devolver el tipo de combustible del coche, por defecto son todos gasolina pero el comercial sera diesel.
Puedes fijarte que a la enumeracin se incluye getCombustible, pero en COMERCIAL se han abierto unas llaves donde se define el mismo mtodo, es decir, lo est sobrescribiendo. Mientras que para el DEPORTIVO y el TURISMO el combustible devuelto ser gasolina, el COMERCIAL devolver diesel.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 48 6.1 Encapsulacin La encapsulacin consiste en el acceso a las variables de la clase mediante un mtodo en lugar de hacerlo directamente. Bueno, y esto para qu sirve? Imagnate que estas creando un cdigo donde ests trabajando con un puado de personas, que no conocen las clases que has hecho, y la misma situacin es la tuya, tu no conoces su trabajo aunque estis participando en el mismo proyecto, te va sonando L2J? Si accedieses directamente a las variables podras pasarle tipos errneos. Que es un tipo? Un tipo es cada clase creada para trabajar con ellas, cada objeto que se crea o existe en Java, es un tipo. Otra ventaja es el mantenimiento del cdigo. Si en tu cdigo hubiera que corregir el cdigo y otro programador usase tu clase mediante los mtodos de la clase, este programador no necesitar saber siquiera los cambios que hagas en tu programa, no se enterar. Por ejemplo:
Aqu tenemos el hipottico caso en que un programador ha creado la clase Arma, y otro programador que la est usando. Como vemos, puede declarar un Arma con una potencia infinita. Si Coder crease un arma con potencia cien millones y resultase que esa arma descompensase el server (porque el jugador se hiciese invulnerable, por ejemplo), habra que arreglar este bug!
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 49 Como arreglar este bug sin que Coder tenga que editar su cdigo? Bien, pues Magneto lo nico que tiene que hacer es limitar la potencia del arma:
Magneto rescribe su cdigo, si la potencia es mayor de 100, entonces la potencia es 100. De esta manera Coder no tiene que editar su cdigo, ni se ha enterado, l sigue haciendo lo suyo sin tener que mirar tu cdigo. Los beneficios que recibes pensando en POO es flexibilidad y mantenimiento. La habilidad de hacer cambios en tu cdigo sin romper el cdigo de otros programadores es la clave de la encapsulacin. Cuando creas una serie de mtodos accesibles desde otras clases (y manteniendo tus implementaciones ocultas para proteger tu clase), estas creando APIs. Para conseguir mantenimiento, flexibilidad y extensibilidad debes seguir estas premisas: Las variables de la instancias deben estar protegidas, el modificador de acceso normalmente, privado. Crea mtodos de acceso pblico para forzar a otros programadores a acceder directamente a los mtodos en lugar de a las variables. Usa la convencin de JavaBeans, setNombreMetodo, getNombreMetodo.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 50 Veamos ejemplos:
Como habamos dicho antes, las variables de instancia han de ser privadas, de tal manera que el programador no pueda acceder directamente a ella. Ahora la nica manera de seleccionar la potencia del arma es mediante el mtodo setPotencia.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 51 Encapsulada la variable de clase y protegiendo el exceso de potencia mediante nuestro cdigo, an tenemos un posible error que controlar, os pongo el cdigo:
El error es que Coder an podra crear un arma con potencia -100, pero te diste cuenta demasiado tarde, ya estn usando el programa. Vas a decirle a Coder que ha ingresado un valor negativo para el arma y que la gente se est quejando porque su arma no mata sino que cuenta chistes?
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 52 NO! Magneto rescribe su cdigo gracias a que ha hecho uso de la encapsulacin.
y Coder ni se entera.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 53 6.2 Polimorfismo El polimorfismo es la posibilidad de que una clase hereda las caractersticas de otra clase para crear una nueva. La clave para usar de buena forma el polimorfismo es preguntarte ES UN? Ejemplo, creamos la clase Coche, y luego creamos Ferrari heredando las caractersticas de Coche. Como saber si lo estamos haciendo bien? Plantate la pregunta, Es un Ferrari un Coche? La respuesta es SI. Ahora creas la clase Mercedes heredando las caractersticas de Ferrari. Ambos son coches, parece estar bien, pero si te preguntas Un Mercedes es un Ferrari? La respuesta es NO, as que estas liando los objetos. Con este truco jams te equivocars. Recuerda, ES UN. Para usar esta caracterstica usamos la palabra clave extends. En que consiste la herencia? La herencia consiste en heredar todas las propiedades de una clase. La utilidad de esto es que aadiendo nuevas propiedades creas nuevos objetos. Ejemplo, la clase Coche lleva ruedas, puertas, frenos, motor. La clase Ferrari lleva adems de lo que lleva un Coche, un caballo como smbolo, el constructor es Minielli y el diseador es Montiveri (por decir cualquier cosa). La clase Spider que hereda a Ferrari, adems de lo que lleva Ferrari, y de lo que lleva un Coche, mide 5 metros y alcanza los 295Km/h. Podramos sacar una nueva clase de Ferrari heredando Ferrari, o podramos sacar un Coche nuevo como Mercedes heredando Coche, o incluso podramos sacar un CocheVoladorSubmarino heredando Coche y aadiendo las caractersticas de un coche que vuele y se sumerja.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 54
En este ejemplo vemos cmo se crea Coche, CocheVolador y CocheVoladorSubmarino, donde CocheVolador aparte de tener alas y flaps propias de un avin, hereda rueda, frenos, puertas y chasis. Ms complejo aun es el CocheVoladorSubmarino, que aparte de llevar timn, vela y mastil propias de un barco, lleva alas y flaps del CocheVolador, y como el CocheVolador hereda Coche, CocheVoladorSubmarino tambien hereda ruedas, frenos, puertas y chasis. Aparte de sus variables de instancia, tambin heredarn sus mtodos, como podra ser frenar() (para el Coche), despegar() (para el coche volador) e inmersin() (para el coche volador submarino). Y si quisiera hacer un CocheTanque? Pues... heredara las propiedades de un Coche y le aado las caractersticas de un Tanque. La nica manera de acceder a un objeto es a travs de una variable de referencia, es decir, la variable que usas con new, en el ejemplo podemos ver que mi referencia a un coche volador submarino es DelfinConAlas. Tienes que saber que la variable de referencia slo puede ser de un slo tipo, es decir, aunque DelfinConAlas es el resultado de la herencia de un Coche y de un CocheVolador, el tipo es CocheVoladorSubmarino y nada ms.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 55 A la variable de referencia le puedes asignar otros objetos, a menos que sea declarada como final. Es decir:
Una variable de referencia tambin puede referirse a cualquier objeto del mismo tipo declarado en la referencia, incluso puede hacer referencia al subtipo declarado.
A esto se le llama casteo que lo veremos en profundidad. En el ejemplo vemos que declaro un CocheVoladorSubmarino donde la variable de referencia est referida a un CocheVolador. Como es del mismo subtipo, el compilador no lanza error y lo acepta como correcto. Una variable de referencia tambin puede ser declarada como un tipo de clase o un tipo de interfaz. Si se declara como un tipo de interfaz puede referenciar cualquier objeto de cualquier clase que implemente la interfaz.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 56
En el ejemplo la variable de referencia est declarada como interfaz Frenar pero se inicializa como CocheVoladorSubmarino, ya que CocheVoladorSubmarino implementa la interfaz Frenar. Al implementar una interfaz (lo habamos visto antes) se deben implementan los mtodos declarados, pero el cdigo de los mtodos abstractos tiene que ser escrito por ti. Fjate que la nica clase que implementa los mtodos es Coche, CocheVolador y CocheVoladorSubmarino no lo escriben. Eso es, como ya dije antes, que heredan sus mtodos, y no hace falta volver a escribirlos. Es ms, si se rescriben, estaras sobrescribiendo los mtodos de la clase que se hereda, o sea, creando unos nuevos. Esto est bien cuando el cdigo del mtodo no es suficiente para la clase que lo hereda.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 57 6.3 Casteo de variables de referencia Como hemos visto en el tema anterior, un casteo consiste en cambiar de un tipo a otro tipo, siendo el otro tipo un subtipo, es decir, un casteo de Ferrari a Coche es posible, pero no uno de Ferrari a CocheVoladorSubmarino. Es un Ferrari un CocheVoladorSubmarino? NO! Acurdate siempre de este truco. En el casteo existen dos direcciones, subir en la escala de la herencia, que se denomina upcasting y el compilador funciona explcitamente (es decir, no tienes que indicarle que ests haciendo un casteo) y bajar en la escala de herencia, denominado downcasting, donde si tienes que indicar explcitamente el casteo. Ejemplo:
Aqu vemos que se declara c1 como Clase1 y se hace un casteo a la Clase4. Como la herencia es ascendente, no hace falta indicar expresamente el casteo. Pero al hacerlo al revs (downcasting):
el compilador se queja, indicar el casteo se hace obligatorio.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 58 Pero, qu pasa si una vez casteado, queremos usar el mtodo de otro tipo?
El casteo ahora est hecho correctamente, el compilador est feliz por la aclaracin, pero al ejecutar el programa, sorpresa...
Por qu ocurre esto? Por qu el compilador no nos ayuda y ver que Clase1 y Clase4 son del mismo subtipo? El compilador lo nico que puede hacer es confirmar que ambos tipos pertenecen al mismo rbol de la herencia. En un upcasting, el nmero de mtodos se restringe, as que no existe la posibilidad de que un mtodo de una clase se haya sobrescrito, al contrario que ocurre con un downcasting. El punto es que ninguna referencia de tipo Clase4 puede hacer llamadas seguras a una instancia de Clase1. Ojo, con esto no digo que el downcasting est prohibido. Si el compilador ve que hay posibilidad de que en tiempo de ejecucin funcione, compilar.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 59 En este ejemplo vemos como el downcasting si est permitido. Explico el ejemplo. La clase Object es la clase de la que derivan todas las clases en Java, es la primera clase. La clase String es una clase derivada de Object que contiene cadenas de texto. Como la referencia o es una cadena de texto, cuando hacemos downcasting de Object a String, el compilador ve que la referencia es una cadena de texto, el mismo tipo que hace referencia o, y no da error. Esto compila sin problemas.
Aunque es raro usar esto de esta manera, nunca est de ms saber que existe y como funciona.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 60 6.4 Implementando una interfaz Al crear interfaces te aseguras que otro programador seguir las reglas que tu creaste para el comportamiento de una clase. Por ejemplo, si creas una interfaz como Volador te aseguras que alguien que cree un objeto que vuele tenga los mtodos que necesitas para poder hacer que ese objeto vuele.
En el ejemplo vemos la implantacin forzosa de los mtodos que nos supone usar la interfaz Volador. Los comentarios los aade automticamente Eclipse al aceptar implementar los mtodos de la interfaz. @Override significa sobrescribir, y eso es lo que tenemos que hacer, crear cdigo para que esta clase pueda volar. Esos mtodos sern invocados desde otras clases que ya presumen que todos los objetos que vuelan podrn realizar las acciones que indica la interfaz.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 61 Aunque el compilador no se va a quejar de que no pongas nada en los mtodos que implementas, no quiere decir que ests haciendo una buena implementacin, por eso hay que seguir esta serie de reglas: Proveer de implementaciones no abstractas de todos los mtodos de la interfaz. Usar las reglas de la sobrescritura, es decir, debe devolver el mismo tipo. Declarar las excepciones no declaradas en los mtodos implantados que son declarados en el mtodo de la interfaz o subclase. Veremos cmo se hace esto ms adelante. Mantener el nombre del mtodo de la interfaz y el mismo tipo o subtipo. Una implementacin tambin puede ser abstracta por si misma, es decir, una interfaz puede heredar otra interfaz, o ms de una, y no tiene que declarar los mtodos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 62 Mientras que una clase slo puede heredar una clase, una interfaz puede heredar mltiples clases. Pero una interfaz no puede implementar nada aunque una clase puede implementar mltiples clases.
Las interfaces son siempre pblicas, aunque no lo declares explcitamente. Los mtodos implementados de la interfaz, han de ser pblicos, no puedes usar los modificadores private, final, protected, o default. Recuerda, que extends se usa para heredar otra clase, e implements se usa para clases abstractas o interfaces. Las clases abstractas tienen mtodos no implementados (sin cuerpo) y deben ser sobrescritos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 63 6.5 Tipos de retornos en constructores sobrecargados Sobrecargar un mtodo es crear otro mtodo con el mismo nombre pero aceptando diferentes parmetros.
Tambin se puede sobrecargar un mtodo cuando una clase hereda a otra (heredando sus mtodos) y rescribes el mtodo.
Cuando se crean mtodos que devuelven tipos distintos, segn los parmetros dados en el mtodo, el tipo de retorno es distinto.
Lo que no puedes hacer es rescribir el mtodo en lugar de sobrecargarlo, as sin ms:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 64 Si quieres rescribir el mtodo en tu subclase, es decir, sobrescritura, puedes cambiar el tipo de retorno si el tipo es un subtipo de la superclase.
En este ejemplo int y byte son distintos tipos, pero pueden ser casteados, es decir, si el valor de int no supera el valor de 255 que es el rango mximo de byte, puede funcionar sin errores en tiempo de ejecucin. Otro ejemplo:
Aqu Main hereda Uno, as que Main automticamente es subtipo de Uno, por eso el retorno del tipo es correcto.
6.5.1 Devolviendo un valor Hay cinco sencillas reglas para devolver un valor. 1. Puedes devolver null en un mtodo con un objeto de referencia de tipo return.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 65 2. Puedes devolver un array. Aunque no hemos visto como se construye un array, en el ejemplo se puede observar que se incluye unos corchetes [] al lado del tipo de devolucin, para indicar que se trata de un array, y dentro del mtodo, al inicializar la variable con los valores.
3. En un mtodo con tipo de retorno primitivo, puedes devolver cualquier valor o variable que pueda ser convertida implcitamente al tipo declarado. Esto es lo que vimos antes del casting.
4. Si el mtodo usa void (vaco) se presume que no devuelve nada, o sea, un valor vaco. Hacer que devuelva un valor es ilegal:
5. Un mtodo que use un objeto de referencia, puede devolver cualquier tipo que pueda ser casteado implcitamente al tipo de retorno.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 66 6.6 Autoboxing Esta caracterstica consiste en convertir tipos automticamente, y es una caracterstica aadida en Java 5. Antes de existir esto, era ms complicado hacer una conversin evidente:
y ahora:
Donde se puede hacer autoboxing? La regla general es que el boxing y unboxing funcionan cuando normalmente usas un dato primitivo o un envoltorio (o sea, el nombre del objeto como Integer).
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 67 7.1 Construccin, reglas y sobrecargas de constructores
Cuando instancias un objeto con new se invoca el constructor de la clase siempre, pero adems de esto, se ejecuta el constructor de la superclase, es decir, se ejecutan todos los constructores de su superclase, y la ltima clase, de donde nacen todas las clases es Object. Un constructor por defecto es como esto:
Lleva el mismo nombre de la clase y entre llaves no hay nada. Este constructor no es necesario crearlo, el compilador lo hace por ti. Los constructores normalmente se usan para inicializar las variables de la instancia, es decir, los valores de las variables de la clase instanciada:
La palabra clave this se usa para hacer hincapi en que nos referirnos a la variable de instancia, no a las variables del mtodo que tienen el mismo nombre. Adems, Eclipse pinta de azul las variables de la instancia siempre que entienda que te refieres a ellas.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 68 Cuando creas un constructor, el constructor por defecto se omite, as que si quieres crear un Circulo sin pasar los parmetros que has establecido, dar error:
Las opciones que muestra Eclipse para arreglar el error es: Aadir los argumentos que encajen con Circulo(int, int, int) Cambiar el constructor Circulo(int, int, int): Quitar los parmetros int, int, int Crear el constructor Circulo() Como ves, si uno de los consejos es crear el constructor que debera estar por defecto, es que ya no est ah. Aunque sea deseable siempre tener un constructor sin argumentos para una clase, muchas veces, como en el ejemplo, no tiene sentido u ocasionara un error. Puedes crear tantos constructores como quieras dentro de una clase. Las reglas para crear un constructor: Los constructores pueden usar cualquier modificador de acceso. El nombre del constructor tiene que ser el mismo que el de la clase. Los constructores no devuelven nada (no tienen return). Es legal aunque estpido tener un mtodo con el mismo nombre que la clase. Esto no significa que sea un constructor. Si no se crea un constructor, el compilador crea uno por defecto, aunque no se vea en el cdigo. El constructor por defecto nunca lleva argumentos. Si has escrito un constructor y quieres otro sin argumentos, tendrs que hacerlo t mismo. Cada constructor invoca implcitamente a this o super. Si no incluyes this o super, el compilador lo har por ti, con o sin argumentos. No se puede invocar a ninguna parte de una instancia hasta que su constructor se haya ejecutado. Solo las variables estticas y mtodos pueden ser accedidas con super o this.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 69 Las clases abstractas tambin tienen constructores, son ejecutados cuando la subclase que los instancia son ejecutadas. Las interfaces no tienen constructores, como no son parte de ningn objeto, no forman parte de ningn rbol de herencia.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 70 7.2 Encadenamiento de constructores Los constructores solo se ejecutan cuando usamos new en alguna clase, pero no slo se ejecuta este nico constructor. Al iniciar un constructor, tambin se inicia el de su superclase, hay un comando que se usa implcitamente, se ejecuta super(), y sirve para invocar a la superclase, y as sucesivamente hasta llegar a la superclase de todas las clases, Object. Para ver el efecto domin, miremos este ejemplo:
La clase Main crea una instancia de la Clase4, pero fjate que antes de ejecutarse el constructor de la clase 4, se ejecuta primero el de la superclase ms alta hasta llegar a la clase 4. Cuando se ejecuta un mtodo sin usar super, en este ejemplo, info, se ejecuta el de la clase que sobrescribe al de la superclase:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 71 Pero si quitamos el mtodo de la clase 4, se ejecuta el de la clase 1, lo mismo que si hubiramos usado super(), solo que el compilador ya lo hace por nosotros:
Aqu inserto super() en la clase 4:
En este ejemplo, se usa super para invocar al constructor de la superclase, pero si te fijas, al pasarle solo un argumento, se ejecuta el constructor de la clase2 sin arrojar error:
Al pasar 2 argumentos da error, porque no hay constructores con dos argumentos:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 72 Finalmente, si instanciamos la clase 1, la clase 2 podr leer las variables de la superclase:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 73 8.1 Mtodos y variables estticas Hay que hacer una distincin entre las variables y variables marcadas como estticas. Las variables no estticas se resetean en cada nueva clase instanciada, mientras que la variable esttica pertenece a la clase, en lugar de a la instancia. Estudiemos este ejemplo:
Mientras que numero ha sido declarado sin el modificador static, es inicializado en cada instancia de la clase, mientras que conteo suma uno cada vez que se ejecuta el constructor, es decir, cada vez que se usa new. En ambas clases instanciadas, conteo tiene el mismo valor, ya que es esttico, no es una variable de la instancia, sino que es una variable esttica, que pertenece a la clase, no a sus copias. Esto tambin es aplicable a los mtodos estticos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 74 8.2 Accediendo a mtodos y variables estticas En el momento en que no necesitas una instancia para acceder a los mtodos o variables estticas usaremos el operador punto(.). Reglas que debes conocer:
Adems los mtodos estticos no pueden ser rescritos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 75 9.1 Funcionamiento del recolector de basuras Vamos a ver lo que queremos decir cuando hablamos del recogedor de basuras en la tierra de Java. A diez mil metros de altura, el recolector de basuras es la frase que se usa para describir el manejo de memoria en Java. Cuando un programa se ejecuta (en Java, C, C++, Lisp, Ruby...) usa la memoria de diferentes maneras. No vamos a meternos en la ciencia 101 de la computacin, pero lo tpico de la memoria es que se use para crear una pila en el Heap, que es la piscina donde Java pone sus mtodos y sus constantes. El Heap es la parte de la memoria donde los objetos de Java viven, y es una y nica parte de memoria que esta de cualquier modo envuelta en el proceso del recolector de basuras. As, que la directiva del recolector de basuras es liberar al Heap, para dejar libre el mayor espacio de memoria disponible. Lo que hace es borrar los objetos que no son alcanzables por el programa Java que est corriendo. Hablaremos ms cuando lleguemos al siguiente punto. Cuando el recolector de memoria se ejecuta, su propsito es encontrar y borrar objetos que no pueden ser alcanzados. Imagina un programa Java que es el comienzo de un bucle de creacin de objetos (que estn en el Heap), y que elimina los objetos cuando no se necesiten ms, crear nuevos objetos, descartarlos, etc... la pieza que falta es el recolector de basuras. Cuando se ejecuta, buscara esos objetos descartados y los borrara de la memoria descargndola para que pueda continuar. Ah, el gran circulo de la vida.
9.1.1 Cuando se ejecuta el recolector de basuras? El recolector de basuras funciona bajo el control de la JVM. La JVM decide cuando se ejecuta el recolector de basuras. Dentro de tu programa Java puedes pedir a la JVM que ejecute el recolector de basuras, pero no hay garantas, bajo ninguna circunstancia, de lo que la JVM va a hacer. La JVM ejecutar el recolector cuando la memoria alcance mnimos. La experiencia me indica que cuando le pides a la JVM que ejecute el recolector, la JVM garantiza que ser ejecutado en corto plazo y justo cuando crees que puedes contar con ello, JVM omite tu peticin
9.1.2 Cmo funciona el recolector de basuras? No puedes estar seguro. Habrs podido escuchar que el recolector de basuras funciona con un algoritmo de barrido, y para cualquier implementacin de Java puede ser cierto, pero la especificacin de Java no garantiza ninguna implementacin en particular. Podras haber odo que el recolector de basuras usa un conteo de referencia, una vez quizs si, quizs no. El concepto ms importante de es: Cuando el objeto es elegido para ser anulado por el recolector de basuras? Para contestar a esta pregunta, tenemos que dar un salto hacia delante y hablar de hilos. En un programa de Java, cada programa tiene desde uno a varios hilos. Cada hilo tiene su propia pequea pila de ejecucin. Normalmente, tu (el programador) crea al menos un hilo para
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 76 ejecutar el programa, el primero con el mtodo main() en el fondo de la pila. Sin embargo, como aprenders en detalle ms adelante, hay muchas razones para lanzar hilos de ejecucin adicionales desde tu hilo principal. Aparte de tener su propia pila de ejecucin, cada hilo tiene su ciclo de vida. Por ahora, todo lo que necesitamos saber es que los hilos pueden estar vivos o muertos. Con esta informacin, podemos decir con contundente claridad que un objeto es elegido para el recolector de basuras cuando no hay hilos vivos accediendo a el. Basndonos en esta definicin, el recolector de basuras hace algo de magia, operaciones desconocidas, y cuando descubre un objeto que no puede ser alcanzado por un hilo vivo, considera que el objeto es elegible para ser eliminado, puede llegar incluso a borrarlo en el mismo momento. (Si, lo adivinaste, puede ocurrir que tampoco lo llegue a borrar nunca). Cuando hablamos sobre el alcance de un objeto, estamos hablando realmente sobre tener una variable de referencia alcanzable que se refiera al objeto en cuestin. Si nuestro programa Java tiene una variable de referencia que hace referencia al objeto, y esa variable de referencia est disponible en un hilo vivo, entonces ese objeto se le considera alcanzable. Hablaremos ms sobre como los objetos puede convertirse en inalcanzables en la siguiente seccin. 9.1.3 Puede una aplicacin Java quedarse sin memoria? S. El recolector de basuras intenta borrar todos los objetos de la memoria cuando no se usan. Sin embargo, si mantienes muchos objetos vivos a la vez (objetos referenciados por otros objetos) el sistema puede llegar a quedarse sin memoria. El recolector de basuras no puede asegurar que haya suficiente memoria, solo que la memoria disponible ser manejada de la forma ms eficiente posible.
9.2 Escribir cdigo que maneje explcitamente objetos elegibles para ser borrados En esta seccin vamos a mostrar cmo hacer objetos elegibles para el recolector de basuras usando el cdigo actual. Tambin vamos a discutir cmo forzar al recolector de basuras si es necesario, y como podemos ejecutar una limpieza adicional en objetos antes de que sean borrados de la memoria. Una referencia nula Como hemos visto antes, un objeto se convierte en apto para ser borrado cuando no hay referencias que lo apunten. Obviamente, sino hay referencias, no importa lo que le ocurra al objeto. Para nuestro propsito es solo algo flotando en el espacio, sin usar, inaccesible y que ha dejado de necesitarse. La primera manera de borrar una referencia a un objeto es seleccionar la variable de referencia que apunta al objeto y volverlo null. Examina el siguiente cdigo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 77
El StringBuffer con el valor "hello" se le asigna la variable sb en la tercera linea. Para hacer este objeto apto para el GC (Garbage Collector, recolector de basuras), le asignamos a sb el valor de null, lo que elimina la nica referencia que exista al objeto StringBuffer. Una vez que la lnea 6 se ejecuta, nuestro pequeo "hello" est condenado para el GC.
9.3 Reasignado una variable de referencia Tambin podemos desemparejar una variable de referencia de un objeto asignndole a la referencia, otro objeto. Examina este cdigo:
Los objetos creados en un mtodo tambin necesitan ser considerados. Cuando un mtodo se invoca, ninguna variable local existe ms all de la duracin del mtodo. Una vez el mtodo ha terminado, el objeto creado en el mtodo es apto para el GC.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 78 Hay una excepcin obvia. Si se devuelve un objeto del mtodo, su referencia puede ser asignada a una variable de referencia en el mtodo que lo llam, as que, no ser apto para la coleccin. Examina este cdigo:
En el cdigo hemos creado un mtodo llamado getDate() que devuelve un objeto Date. Este mtodo crea dos objetos: un Date y un StringBuffer que contiene la informacin. En el momento que el mtodo devuelve el objeto Date, no ser apto para la GC aunque el mtodo se haya completado. El StringBuffer ser apto, aunque no lo hayamos hecho explcitamente, la variable ahora tiene asignado un null.
9.4 Aislando una referencia Hay otra manera en la que los objetos se conviertan en aptos para la GC, aunque tengan unas referencias vlidas. Nosotros llamamos a este escenario "isla de la soledad". Un ejemplo simple es que una clase que tiene una variable de instancia que es variable de referencia a otra instancia de la misma clase. Ahora imagnate que las dos instancias de la misma clase existen y que la una y la otra estn apuntndose. Si las otras referencias a estos objetos son eliminadas, entonces incluso aunque estas referencias sean vlidas, no hay hilo que acceda a estas variables de referencia. Cuando el GC se ejecuta, puede normalmente, encontrar estas islas y eliminarlas. Como te puedes imaginar, estas islas pueden llegar a ser bastante grandes, tericamente contiene cientos de objetos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 79 Examina el siguiente cdigo:
Cuando el cdigo alcanza //, las tres islas previamente conocidas como i2, i3 e i4, tienen variables de instancias que apuntan las unas a las otras, pero sus enlaces hacia el mundo, ha sido anuladas. Estos tres objetos son aptos para la GC. Esto cubre todo lo que necesitaras saber sobre crear objetos aptos para la GC.
9.5 Forzando el recolector de basuras La primera cosa que debera de mencionarse aqu es eso, contrariamente al ttulo de esta seccin, el GC no puede ser forzado. Sin embargo, Java provee de mtodos que te permiten solicitar que la JVM efectu la ejecucin del GC. Por ejemplo, si estas a punto de ejecutar algunas operaciones sensibles, probablemente querrs minimizar el riesgo de lag causado por el recolector de basuras. Pero tienes que recordar que los mtodos que Java provee son peticiones, no demandas, la JVM har lo mejor respecto a lo que solicitas, pero no hay garantas de que efectuar la peticin. En realidad, solo es posible sugerir a la JVM que ejecute el GC. Sin embargo tampoco hay garantas de que elimine todos los objetos sin usar de la memoria (aunque el GC se ejecute). Es esencial que entiendas ese concepto para el examen. La rutina del GC que Java suministra son miembros de la clase Runtime. Esta es una clase especial que solo tiene un objeto (un Singleton) para cada programa. El objeto Runtime provee de mecanismos para comunicar directamente con la mquina virtual. Para conseguir una instancia de Runtime, puedes usar el mtodo Runtime.getRuntime(), que te devuelve el Singleton. Una vez que lo tengas, puedes invocar al recolector de basuras usando el mtodo gc(). Alternativamente, puedes invocar al mismo mtodo en la clase System, que es un mtodo esttico que puede funcionar obteniendo el Singleton para ti. La manera ms simple para pedirle al GC que se ejecute es:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 80 Tericamente, despus de llamarlo, tendrs mucha memoria libre. Decimos tericamente porque esta rutina no funciona siempre de esa manera. Primero, tu JVM no puede tener implementada esta rutina; la especificacin del lenguaje no permite hacer nada. Segundo, otro hilo puede ganar un montn de memoria en el momento que se ejecute el GC. Esto no es decir que System.gc() es un mtodo intil, es mucho mejor que nada. Simplemente no puedes confiar en System.gc() para liberar suficiente memoria, as que no tienes que preocuparte sobre quedarte sin memoria. Ahora que de alguna manera nos hemos familiarizado con cmo funciona, hagamos un pequeo experimento para ver si podemos ver los efectos del GC. El siguiente programa nos permitir saber cunta memoria tiene disponible la JVM y cuanta ha libreado. Esto va a crear 10.000 objetos Date. Despus, le dir cuanta memoria queda, llamar al GC (el cual decidir si se va a ejecutar, el programa se detendr hasta que todos los objetos sean eliminados). La memoria final debera indicarse cuando se haya ejecutado. Veamos el programa:
Ahora veamos el resultado:
Como puede verse, la JVM ha decidido recolectar la basura de los objetos aptos para ser eliminados. En el ejemplo, le sugerimos a la JVM que ejecutase el GC con 458Kb de memoria restante, y nos honr con su aparicin. Este programa solo tiene un hilo corriendo, as que no haba nada ms funcionando cuando fue ejecutado. Ten en mente que el comportamiento de gc() cuando es ejecutado puede ser diferente, as que no hay garanta que los objetos sin uso
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 81 sean eliminados de la memoria. La nica cosa que se garantiza es que el GC funcionara antes de arrojar una excepcin OutOfMemoryException.
9.6 Limpiar antes de ejecutar el GC - el mtodo finalize() Java provee de un mecanismo para ejecutar un cdigo justo despus de que tu objeto sea borrado por el GC. Este cdigo est en un mtodo llamado finalize() que todas las clases heredan de Object. Sobre el tapete suena como una gran idea, quizs tu objeto consuma algo ms de recursos, y te gustara cerrarlo antes de que sea borrado. El problema es ese, que no puedes contar con el GC siempre para borrar un objeto. As, que cualquier cdigo que pongas dentro de tu clase, el mtodo finalize() tampoco te garantiza que se vaya a ejecutar, as que tampoco es recomendable que pongas cdigo esencial dentro de este mtodo. El caso, es que recomendamos que no sobrescribas el mtodo finalize(). Un pequeo truco para finalize() Hay un par de conceptos concernientes a este mtodo que necesitaras recordar: Para cualquier objeto dado, el mtodo ser llamado una vez por el GC. Llamar a este mtodo puede acabar en que el objeto sea salvado del borrado. Miraremos estos estamentos ms adelante. Lo primero de todo, recordar que el cdigo que pongas dentro de un mtodo normal, puedes ponerlo en finalize(). Por ejemplo, en el mtodo finalize() podras escribir el cdigo que pasa una referencia a un objeto en cuestin hacia otro objeto, efectivamente, el objeto acaba en el GC. Si en el mismo punto, ms tarde en este mismo objeto se convierte en apto para el GC, el GC puede pausar este proceso y borrarlo. El GC sin embargo recordar, que en este objeto, finalize() ya se estaba ejecutando, y no va a ser ejecutado otra vez.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 82 10. Operadores Si tienes variables, tendrs que modificarlas. Necesitars incrementarlas, sumarlas, compararlas (hay como una docena de formas). En este captulo, aprenders como se hace todo eso en Java. Los operadores de Java producen nuevos valores desde uno o ms operandos (solo queremos dejarlo todo claro, recuerdo que los operadores son las cosas a la izquierda y derecha del operador). El resultado de la mayora de las operaciones son un valor booleano o numrico. Ya que sabes que Java no es C++, no vas a sorprenderte de que los operadores de Java no son sobrecargados. Sin embargo existen unas pocas excepciones donde los operadores pueden venir sobrecargados. El operador + puede ser usado para aadir dos nmeros o para hacer una concatenacin si el operando es una cadena. Los operadores &, |, y ^ pueden ser usados de dos formas distintas, aunque en esta versin del examen, sus capacidades de bit no sern testadas.
10.1 Operadores de asignacin Cuando asignamos un valor a un primitivo, el tamao importa. Pero asegrate de saber cundo hay un casteo implcito, cuando es el casteo explcito necesario y cuando puede ocurrir la truncacin (por ejemplo, acurdate de que un int puede entrar en un byte siempre que no supere el rango). Recuerda que una variable de referencia no es un objeto, es una manera de conseguir un objeto. (Sabemos que todos los programadores de C++ se mueren por decirnos que eso es un puntero, pero nosotros no.) Cuando asignamos un valor a una variable de referencia, el tipo importa. Recuerda las reglas para los supertipos, subtipos y arrays. Ahora cubriremos unos pocos de detalles de los operadores de y ms adelante, miraremos cmo funciona el asignador = con las cadenas (las cuales, son inmutables).
10.2 Operadores de asignacin compuestos Actualmente hay 11 asignadores, pero solo cuatro son los ms usados (+=, -=,*= y /=) en el examen (depende del objetivo). Los operadores de asignacin compuestos son la manera ms fcil de ahorrar unos pocos golpes de teclado. Aqu hay varios ejemplos de asignaciones, primero, sin usar el operador de compuesto,
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 83 Ahora con los operadores compuestos:
Por supuesto, los resultados sern los mismos.
10.3 Operadores relacionales Hay seis operadores relacionales (<, <=, >, >=, == y !=). Los operadores relacionales siempre dan como resultado un booleano (true o false). Este valor booleano es usado a menudo como sigue:
pero el valor resultante puede ser tambin asignado directamente de booleano a primitivo:
Java tiene cuatro operadores relacionales que pueden ser usados para usarse en la comparacin de cualquier combinacin de enteros, decimales o caracteres: > mayor que >= mayor o igual que < menor que <= menor o igual que Observemos algunas comparaciones validas:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 84 En el cdigo anterior, usamos una comparacin entre caracteres. Tambin es legal comparar un carcter primitivo con un nmero (aunque no sea un gran estilo de programacin). Al ejecutar el cdigo, tendremos la siguiente salida: The animal is a gray elephant
Hemos mencionado que los caracteres pueden ser usados en operadores de comparacin. Cuando comparamos un carcter con otro carcter, o un carcter con un nmero, Java usara el valor Unicode del valor del carcter como valor numrico para la comparacin.
10.4 Operaciones de igualdad Java tiene dos operadores de igualdad (tambin llamados operadores relacionales) que comparan dos cosas similares y devuelve un valor booleano que representa true o false de las cosas que se estn comparando. Estos operadores son: == igual (mejor conocido como igual que) != no igual (mejor conocido como no igual que) Cada comparador individual puede involucrar dos nmeros (incluyendo los caracteres), dos valores booleanos, o dos variables de referencia a objetos. En todo caso, no puedes comparar tipos incompatibles. Cual sera una respuesta si preguntamos si un booleano es igual que un carcter? o si un botn es lo mismo que una cadena de texto? (Exactamente, tonteras, porque no tienen sentido). Hay cuatro tipos diferentes de cosas que pueden ser comparadas: nmeros caracteres booleanos primitivos variables de referencia a objetos As que, que compara == (son dos signos de =)? El valor en la variable, en otras palabras, el patrn de bits.
10.5 Comparacin de primitivos La mayora de programadores estn familiarizados con la comparacin de valores primitivos. El siguiente cdigo muestra algunos test de igualdad sobre variables:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 85
El programa mostrara: character 'a' == 'a'? true character 'a' == 'b'? false 5 != 6? true 5.0 == 5L? true true == false? false Como puedes ver, normalmente si un numero decimal es comparado con un entero y el valor es el mismo, el operador == (dos signos de igualdad =) devuelve true, tal como se esperaba.
10.6 Igualdad para variables de referencia Tal como vimos antes, las dos variables de referencia pueden referirse al mismo objeto, tal como demuestra este cdigo:
Despus de ejecutar este cdigo, ambas variables estn apuntando al mismo objeto. Las variables de referencia pueden ser comprobadas para ver si son el mismo objeto usando el operador igual que(==). Recuerda que este operador examina los bits contenidos en la variable, as que para las variables de referencia significa que si ambas referencias contenidas son iguales, entonces se refieren al mismo objeto. Examina el siguiente cdigo:
Este objeto crea tres variables de referencia. Las primeras dos son dos objetos JButton distintos, mientras que a la tercera se le asigna la primera referencia. Cuando este programa se ejecuta, se muestra el siguiente resultado: Is reference a == b? false Is reference a == c? true Esto nos muestra que la primera y tercera referencia son la misma instancia de JButton. El operador "igual que" no har la comparacin si los objetos son significativamente
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 86 equivalentes, un concepto que cubriremos con las colecciones, cuando veamos el mtodo equals() (lo opuesto a lo que estamos viendo aqu).
10.7 Igualdad para enumeraciones Una vez que has declarado una enumeracin, no se puede expandir. En tiempo de ejecucin no hay manera de aadir nuevas constantes. Naturalmente, puedes tener tantas variables como quieras, as que es importante el poder comparar dos variables de referencia de enumeracin para ver si son iguales, por ejemplo, para ver si se refieren a la misma constante de enumeracin. Tambin puedes usar el operador == o el mtodo equals() para determinar si las dos variables se estn refiriendo a la misma constante de enumeracin:
Sabemos que }} es bastante feo de ver, pero te estoy preparando. Esto da como salida: == dot equals
10.8 Comparacin con instanceof() Este mtodo se usa solo para las variables de referencia, y puedes usarlo para saber si un objeto es de un tipo particular. Por tipo, queremos decir la clase o la interface, en otras palabras, si el objeto referido por la variable de la izquierda pasa el test de ES-UN para el tipo de clase o interface de la derecha
esto imprime: s is a String
Incluso si el objeto que est siendo testeado no es una instancia del tipo de la clase del lado de la derecha del operador, instanceof devolver true si el objeto es compatible con el operando de la derecha.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 87 El siguiente ejemplo demuestra el uso normal de instanceof, verificar si un objeto es instancia de uno de sus subtipos antes de intentar hacer un downcasting:
El cdigo anterior compila y muestra: 'a' refers to a B En el ejemplo, usamos instanceof para proteger al programa de un downcasting ilegal. Puedes testear un objeto de referencia con su propia clase, o cualquiera de sus subclases. Esto significa que cualquier objeto de referencia ser evaluado a true si usas instanceof con el tipo Object, tal como sigue:
lo cual imprime: b is definitely an Object
Hay que aadir, que un valor null es tambin valido en una referencia. Esto siempre dar false:
Esto imprime: false false
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 88 10.8.1 Errores de compilacin con instanceof
No puedes usar instanceof en dos tipos de jerarquas distintas. Por ejemplo, esto no compilara:
La compilacin falla, no hay manera de que d pueda referirse a Cat o a algn subtipo de Cat. El siguiente resumen muestra el uso de instanceof en el siguiente cdigo:
10.9 Operadores aritmticos
Estoy seguro de que estas familiarizado con los operadores aritmticos. + sumar - restar * multiplicacin / divisin Se pueden usar de manera estndar:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 89 10.9.1 El operador resto % Este operador puede que no te sea familiar. Lo que hace es obtener el resultado de dividir los operandos, tal como demuestra este cdigo:
Al ejecutar el cdigo, imprime:
The result of 15 % 4 is the remainder of 15 divided by 4. The remainder is 3 Recuerda: Las expresiones son evaluadas de izquierda a derecha por defecto, Puedes cambiar esta secuencia aadiendo parntesis. Tambin recuerda que *,/ y % preceden sobre + y -.
10.9.2 Operador de concatenacin de cadenas El signo ms puede ser usado para concatenar dos cadenas de caracteres.
La concatenacin se pone interesante cuando combinas cadenas y nmeros:
Que har el operador +? sumar las variables numricas o concatenara los caracteres? Ok, ya has tenido tiempo de pensarlo. Los valores int sern tratados como caracteres y puestos a la derecha de la cadena, dando de resultado:
String37
As que el cdigo se lee como "empieza con cadena, luego cadena "3" y cadena "7". Sin embargo, si usas los parntesis alrededor de las variables numricas tal como se muestra:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 90 tendremos: String10 Al usar los parntesis haces que se evale primero lo que est entre ellos, as que el operador ms a la derecha lo que hace es aadir el resultado del parntesis. Recuerda esta regla: Si el operador es una cadena, el operador ms se convierta en un concatenador de cadenas. Si ambos operadores son nmeros, el operador + hace una suma. Alguna vez encontraras problemas al decidir si el operador de la izquierda es cadena o no. En el examen no lo esperes tan obvio. Observa el siguiente cdigo:
No puedes saber que el operador + se est usando para sumar o concatenar hasta averiguar el tipo de devolucin de foo. Finalmente tienes que saber que es vlido usar el operador += con cadenas:
Como el operador += para hacer una suma, pues el resultado es 1234567.
10.10 Operadores de incremento y decremento
Java tiene dos operadores que incrementan o decrementan una variable en 1. Estos operadores estn compuestos de dos signos mas o dos menos (++ --). El operador se sita despus del operando, o despus para cambiar su valor. Sin embargo, cuando el operador est a un lado u otro, el resultado cambia, veamos este ejemplo:
Observa la 4a lnea del programa donde el operador de incremento esta despus de la variable player. Esto significa que estamos incrementando el valor en 1 pero justamente antes de arrojar el valor en la pantalla. Cuando ejecutamos el programa, aparece esto:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 91 %java MathTest players online: 0 The value of players is 1 The value of players is now 2
Tienes que advertir que la variable escrita en la pantalla, primero dice el valor, y luego efecta la operacin de incremento si el operador esta despus de la variable. La lnea 5 no incrementa la variable, solo est haciendo una concatenacin. La lnea 6 incrementa el valor de la variable antes de ser mostrada en pantalla. Puedes esperar un remix de operadores tal como este ejemplo:
El cdigo imprime: x = 3 y = 4
Esto se lee como "Si 3 es igual a 2 O 3 < 4".
La primera expresin compara x e y, y el resultado es false, porque el incremento de x no sucede hasta que el test == est hecho. Lo siguiente que ocurre es que se incrementa x, as que ahora x vale 3. Luego el segundo checkeo dice que x es menor que y, pero ya hemos incrementado y antes en la comparacin con x, as que la comparacin (3 < 4) es cierta y se muestra el resultado.
10.11 Operador condicional
El operador condicional es un operador ternario (tiene tres operandos) y se usa para evaluar una expresin booleana, se parece mucho a if, solo que en lugar de ejecutar un bloque lo que hace es asignarle un valor a la variable. Su construccin es como sigue:
Puedes leer que el nmero de pets es 3. Los siguiente que hacemos es asignar el estatus a la variable. Si el nmero de pets es menor que 4, le asigna un mensaje, de otra manera, le asigna el otro.
El operador condicional comienza por una operacin booleana seguida de dos posibles valores a la izquierda del operador =. El primero valor (el de la izquierda del :) se asigna si la condicin se cumple, y el segundo valor se asigna si la condicin no se cumple. Puedes incluso anidar operadores condicionales en un solo estamento:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 92
10.12 Operadores lgicos
Hay seis operadores lgicos (&, |,^, !, &&, ||). En alguna documentacin de Sun se usa otra terminologa para estos operadores, pero nuestro propsito son los seis de arriba.
10.13 Operadores e Bitwise
Okey, esto puede ser confuso. De los seis operadores lgicos listados arriba, tres de ellos (&, |,^) pueden ser usados tambin como operadores bitwise. Los operadores de bitwise fueron incluidos en versiones anteriores del examen, pero no estn en el examen de Java 5. Aqu hay varios estamentos que usan operadores de bitwise:
Los operadores de bit comparan dos variables bit a bit, y devuelve una variable cuyos bits han sido basados en cualquier de las dos variables y siendo comparados sus bits con AND (&), otro con OR(|) y otro con ON(^), la consola muestra:
0 15 1
10.14 Atajo para operadores lgicos Hay cinco operadores lgicos que son usados para evaluar estamentos que contienen ms de una expresin booleana. La mayora de los ms usados tienen dos atajos sintcticos, son AND, y OR. Se representan: && AND || OR
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 93 Para que la condicin AND se cumpla, tiene que ser todo cierto, mientras que con OR es cierto si cualquiera de las comparaciones es verdadera. Estos atajos se evalan desde la izquierda a la derecha, si alguna condicin no se cumple, no se sigue evaluando el estamento. class Logical { public static void main(String [] args) { boolean b = true && false; System.out.println("boolean b = " + b); } } esto no muestra
%java Logical boolean b = false
Presta atencin al siguiente ejemplo:
da como resultado
% java TestOR i < 5 Result is true i >= 5 i >= 5
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 94 Aqu esta lo que ha pasado en el mtodo main(): 1. Cuando llegamos a la lnea 3, se evala el primer operando con || 2. El mtodo isItSmall(3) se invoca e imprime "i < 5" y devuelve true 3. El operando de la lnea 3 es cierto, el operador || no evala la siguiente comparacin as que nunca vemos "i >= 5" que se hubiera mostrado si se hubiera ejecutado el segundo estamento. 4. Se evala la lnea 6, comenzando con el primer operando || 5. El mtodo isItSmall(6) se invoca imprimiendo "i >= 5" y devolviendo false. 6. Como el primer operador || de la lnea 6 es false, el operador || no puede saltar el segundo operando, porque todava hay una expresin que puede ser verdad, si se evala el segundo operador dar true. 7. Se invoca isItSmall(9) que imprime "i >= 5". 8. El mtodo isItSmall(9) devuelve false as que la expresin de la lnea 6 es falsa, por lo que la lnea 7 nunca se ejecuta.
10.15 Operadores lgicos sin atajos Hay dos operadores lgicos, &, AND y | OR. Estos operadores son usados en expresiones lgicas al igual que && y ||, pero no son atajos, estos evalan ambos lados de la expresin siempre. Son ineficientes. Por ejemplo, si el primer operando con expresin & es falso, el segundo operando tambin se evaluara, aunque el resultado, evidentemente sea false. Y el OR tambin es ineficiente, si el primer operando es true, JVM todava evaluara el segundo operador aun sabiendo que el resultado dar true.
10.16 Operadores lgicos ^ y !
Los ltimos operadores lgicos son: ^ XOR y ! booleano invertido. El OR exclusivo (o XOR) slo evala valores booleanos. El operador ^ es tratado como un operador sin atajo y siempre evala ambos operandos en una expresin. Para el XOR, la expresin para que d true tiene que ser EXACTAMENTE que uno de los operandos sea true, por ejemplo:
resulta: xor false
La expresin anterior devuelve false porque ambos operandos son verdaderos. El operador ! devuelve el valor contrario del booleano:
se puede leer como "si no es verdad que 7 == 5," y la salida produce
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 95 not equal Aqu hay otro ejemplo de booleano:
da como resultado: ! true false En el cdigo anterior tienes que fijarte en que el test & es aprobado (imprimiendo true) y que el valor de la variable booleana f no cambi, as que imprimi false.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 96 11 Control de flujo, excepciones y aserciones Como te imaginarias escribiendo un cdigo usando un lenguaje que no te permitiese ejecutar estamentos de forma condicional? El control de flujo es la clave de la mayora de los lenguajes de programacin, y Java ofrece varias maneras de hacerlo. Algo como if o el bucle for son estamentos comunes en la mayora de los lenguajes. Pero Java tambin arroja un par de controles que podras no haber usado antes, las excepciones y las aserciones. El estamento if y switch son de tipo condicin/decisin que permite a tu programa tener diferentes comportamientos dependiendo del resultado de un test lgico. Java provee de tres constructores de bucle, for, while y do, as que puedes ejecutar el mismo cdigo una y otra vez dependiendo de que se cumpla una condicin. Las excepciones dan una manera simple para organizar el cdigo de forma sencilla que se ocupa de problemas que pudieran surgir durante la ejecucin. Finalmente, la asercin, aadido en el lenguaje en el 1.4, te da una manera de comprobar y debuguear en condiciones que tu esperas puedan fallar mientras desarrollas, cuando no necesariamente necesites o quieras sobrecargar el manejo de excepciones. Con estas herramientas, puedes construir un programa robusto que pueda manejar cualquier situacin lgica con elegancia.
11.1 Estamento if El if y el switch se refieren normalmente a estamentos de decisiones. Cuando usas un estamento de decisin en tu programa, le estas pidiendo al programa que evale una expresin dada para determinar qu accin coger. Vamos a ver el estamento if. El formato bsico de un estamento if-else La expresin entre parntesis debe evaluarse a booleano. Normalmente, se usa para evaluar una expresin y ejecutar un bloque u otro segn si el resultado es verdadero o falso. El siguiente cdigo demuestra un estamento if-else valido:
El bloque else es opcional, as que tambin puedes usar lo siguiente:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 97 El cdigo asignara un 2 si la evaluacin es true. Las siguientes lneas fuera de las llaves se ejecutaran sin importar el resultado. Hasta las llaves son opcionales si solo quieres ejecutar un nico estamento (el inmediato justo despus del cierre del parntesis):
Ten cuidado con el cdigo de arriba, porque puedes pensar que se lee as:
Si x es ms grande que 3, entonces poner y a 2, la z a z+8 y luego a =y + x.
Pero en realidad las dos ltimas lneas se ejecutarn, no son parte del bloque de condicin.
Podras tener la necesidad de anidar estamentos if-else (no es recomendado para la lectura). Puedes inicializar un if-else para evaluar mltiples condiciones. Los siguientes ejemplos usan dos condiciones, as que si el primer test falla, ejecutaremos un segundo test para decidir qu hacer:
Esto podra rescribirse tal como:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 98 Hay un par de reglas para el uso de if-else-else if: Puedes tener desde cero else hasta uno para cada if, y deben ir despus de cada if. Una vez que else es ejecutado, ninguno de los dems else o if sern ejecutados.
11.2 Estamento switch
Una manera de simular el uso de switch es usar mltiples if. Echa un vistazo al cdigo if-else y fjate como de confuso puede ser tener if anidados, incluso con pocos niveles:
y ahora lo mismo representado con switch:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 99 Por si an no has pillado la estructura de un switch, te lo explico brevemente.
Como cualquier bloque, un switch rodea entre llaves los cdigos. Entre parntesis, switch, evala la variable. En cada caso, case, ejecuta las instrucciones cuando el caso coincide, hasta llegar a break. Si no se pusiese un break, se continuaran ejecutando las dems instrucciones contenidas en los siguientes case. Es opcional. Con default, te aseguras de ejecutar alguna instruccin si no se cumple ningn caso. Es opcional.
11.2.1 Expresiones vlidas para switch y case
El uso general de switch es:
Una expresin switch debe evaluar un carcter, byte, short, int o como en Java 5, una enumeracin. Eso significa que si no ests usando una enumeracin, solo puedes usar variables y valores que puedan ser automticamente ascendidos (en otras palabras, casteados) a int . No va a compilar si usas cualquier otra cosa, incluyendo nmeros long, float o double.
El estamento case evala un valor constante del mismo tipo expresado en switch, con algo adicional, y gran, restriccin: la constante case debe ser una constante en tiempo de ejecucin! Lo que significa que solo puedes usar variables constantes o finales. No es suficiente con que sea una variable final, debe compilar como constante:
switch solo puede evaluar la igualdad. Quiere decir que los operadores como mayor que, menor que, etc.. no se pueden usar en case. Lo siguiente es una expresin vlida usando un mtodo de invocacin en el estamento switch. Fjate que en este cdigo, para que sea vlido, el mtodo est siendo invocado en la referencia del objeto, debe devolver un valor compatible con int.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 100
Qu pasa si usas una variable menor que un int en un switch? Observa el ejemplo:
El cdigo no compilar. Aunque el estamento es vlido, el byte es implcitamente casteado a int, el segundo case (128) es demasiado grande para un byte (hasta 127 positivos) y el compilador lo sabe! Intentar compilar la ltima instruccin da un error como este:
Tampoco no es vlido tener ms de un case usando el mismo valor. Por ejemplo el siguiente bloque no compilara porque usa 2 case con el valor 80:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 101 Es lcito aprovechar la potencia del boxing en una expresin switch. Por ejemplo, esto es vlido:
11.2.2 Interrupciones y flujo en los boques switch
Ya estamos preparados para discutir el estamento break, y mas detalles sobre control de flujo en un switch. Lo ms importante a recordar es que la ejecucin de un switch funciona as:
Las constantes en case son evaluadas desde arriba, hacia abajo, y el primer valor evaluado en case que coincida con la expresin switch , ser el punto de entrada para ejecutar el bloque case.
En otras palabras, una vez que un case sea ejecutado, la JVM ejecutar los dems bloques case siguientes, hasta encontrar un estamento break.
El siguiente ejemplo usa una enumeracin en un estamento case:
En este ejemplo, el case green: encaja, as que la JVM ejecutar ese bloque y los subsiguientes produciendo la salida:
green blue done
De nuevo, cuando el programa encuentra la palabra break durante la ejecucin de un estamento switch, la ejecucin del bloque case finalizara y saldr del bloque switch. Si se omite break, el programa simplemente, ejecutar todos los bloques case hasta que termine el estamento switch. Observa el siguiente cdigo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 102
mostrar:
x is one x is two x is three out of the switch
Esta combinacin sucede cuando el cdigo no encuentra el estamento break, la ejecucin se mantiene hasta el final. Esta clase de ejecucin se la conoce como "fall-through" porque la manera de ejecutarse cae desde el primer case ejecutado hasta el ltimo. Recuerda, que el punto de entrada de ejecucin es el primer case que coincida con la evaluacin de switch. En otras palabras, no puedes pensar "Encuentra la coincidencia, ejecuta el bloque y sal". Porque eso no funciona as. Si t quieres que funcione as, tienes que usar break en cada case como en el ejemplo:
Este cdigo mostrar:
x is one out of the switch
y ya est. Hemos entrado dentro del bloque switch en el case 1. Porque encaja con la evaluacin en switch, hemos conseguido ejecutar el estamento println, luego llega a break y salta al final de switch. Un ejemplo interesante del uso de este fall through se muestra en el siguiente cdigo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 103
El estamento switch imprimir "x is an even number" o nada, dependiendo de si el numero esta entre uno y 10 y es par o impar. Por ejemplo, si x vale 4, la ejecucin comenzara por el case 4 hasta el final.
Nota: Debido a que el fall-through es menos intuitivo, Sun recomienda que aadas un comentario // fall through cuando uses esta lgica.
11.2.3 El caso default
Qu pasa si en el cdigo anterior, tu queras imprimir "x is an odd number" si ninguno de los casos (incluso los impares) encajaba? No podras ponerlo despus del estamento de switch, o incluso en el ltimo case, porque en ambas situaciones, podra imprimir siempre. Para conseguir este comportamiento necesitaras la palabra clave default. (Sin embargo, si t te has preguntado por qu hay una palabra clave default aunque no lo usemos como modificador de acceso, vers ahora que default se usa para un propsito completamente distinto). El nico cambio que necesitamos hacer es aadir un caso por defecto en el cdigo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 104 Los bucles de Java vienen en tres sabores: while, do y for (y a partir de Java 5, for tiene dos variantes). Los tres te permiten repetir un bloque de cdigo tantas veces como se cumple la condicin, o especificas veces de iteraciones. Probablemente estas familiarizado con los bucles en otros lenguajes, as que si eres nuevo en Java, no ser ningn problema aprenderlos.
11.3 Estamento while
Este bucle es bueno en escenarios donde no sabes la cantidad de veces que un bloque de estamentos tiene que repetirse, pero quieres continuar haciendo el bucle mientras la condicin se cumpla. Un estamento while es como esto:
En este caso, como en todos los bucles, la expresin debe evaluarse como un resultado booleano. El cuerpo del bucle se ejecutar mientras la expresin resulte true. Una vez dentro del bucle, el cuerpo se repetir hasta que la condicin sea evaluada a false. En el ejemplo anterior, el programa entrara en el bucle porque x es igual a 2. Sin embargo, x es incrementada en el bucle, as que cuando la condicin se comprueba otra vez, la evaluacin da false y sale del bucle.
Cualquier variable usada en la expresin while debe ser declarada antes de que la expresin sea evaluada, en otras palabras, no puedes decir:
Nuevamente, por qu lo haras? En lugar de evaluar la variable, la declararas y la inicializaras, as que siempre tendra el mismo valor. No se parece mucho a una evaluacin! La clave est en recordar que el bucle while puede ni llegar a ejecutarse. Si la evaluacin devuelve false, el cuerpo de while se ignorara.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 105
El cdigo devuelve:
past the loop
Ya que la expresin (x > 8) se evala falsa, nada en el interior del cuerpo se ejecuta.
11.4 Estamento do while
El uso de do while es similar a while excepto que la expresin no se evala hasta que el cdigo dentro del bucle se ejecuta, as que se garantiza que el cdigo del bloque se ejecutar al menos una vez. El siguiente ejemplo muestra un do-while en accin:
El System.out.println() imprimir una vez, aunque la expresin se evala falsa. Recuerda, el bucle siempre ejecutar el cdigo del cuerpo por lo menos, una vez. Asegrate de usar el punto y coma al final de la expresin while.
El uso de los bucles
En Java 5, los bucles for tienen una segunda estructura. Nosotros llamaremos al viejo estilo, "bsico", y al nuevo estilo "bucle mejorado" aunque Sun se refieren a el como for-each.
Dependiendo de la documentacin que uses (Sun incluida) vers los dos trminos paralelamente con for-in. Los trminos for-in y for-each se refieren al mismo for mejorado. El bucle bsico de for es ms flexible que su homnimo mejorado, pero el mejorado fue diseado para realizar iteraciones a travs de colecciones y arrays.
11.5 Estamento for, o for-in (el bucle bsico)
Este estamento es til cuando sabes de antemano las veces que se ejecutar el cdigo dentro del bloque. Este estamento consta de tres partes adems del cuerpo del bucle:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 106 Declaracin e inicializacin de la variable La expresin booleana La iteracin Las tres partes estn separadas por punto y coma. Los siguientes ejemplos demuestran un bucle for. El primer ejemplo muestra las partes de un bucle for en pseudo cdigo, y la segunda, un ejemplo tpico.
El for bsico: declaracin e inicializacin
La primera parte del estamento te permite declarar e inicializar cero, una o mltiples variables del mismo tipo dentro del parntesis despus de for. Si declaras ms de una variable del mismo tipo, entonces las tendrs que separar con ; (punto y coma) tal como sigue:
La declaracin e inicializacin ocurre antes que nada en el bucle. Y mientras las otras dos partes, la evaluacin booleana y la iteracin, se ejecutarn con cada vuelta de bucle, la declaracin slo suceder una vez al comienzo. Tambin tienes que saber que la vida de las variables declaradas en el bucle, terminan con el bucle.
Este ejemplo lo demuestra:
Test.java:19: cannot resolve symbol symbol : variable x location: class Test System.out.println(x); ^
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 107 El for bsico: la expresin booleana
La siguiente seccin que se ejecuta es la expresin de la condicin, la que (como en todos los test condicionales) debe evaluar un valor booleano. Solo puedes tener una expresin lgica, pero puede ser compleja. Observa el cdigo:
Este cdigo era vlido, pero el siguiente no lo es:
El compilador arrojar:
TestLong.java:20: ';' expected for (int x = 0; (x > 5), (y < 2); x++) { } ^
La regla para recordar esto: Solo puedes tener una expresin lgica.
En otras palabras, no puedes usar mltiples evaluaciones separadas por comas, aunque las otras dos partes del estamento puedan tener mltiples partes.
El for bsico: el operador de iteracin
Despus de cada ejecucin del cuerpo del bucle, se ejecuta la expresin de internacin. Esto es donde le dices lo que quieres que ocurra en cada iteracin del bucle. Recuerda que siempre ocurre despus de que el bucle se complete. Mira lo siguiente:
El cdigo precedente se ejecuta solo una vez. La primera vez, dentro del estamento x vale cero, luego se evala para ver si es menor que uno (lo que es cierto) para despus ejecutar el cuerpo del bucle. Despus de que el cuerpo se haya ejecutado, la iteracin se ejecuta incrementando x en 1. Lo siguiente que toca es evaluar x, pero el resultado ahora es falso, la ejecucin del bucle termina.
Ten en cuenta que, salvo una salida forzada, la evaluacin de la iteracin y la evaluacin del booleano son las dos ltimas cosas que ocurre en un bucle for.
El ejemplo de salida forzada pueden ser un break, un return, un System.exit() o una excepcin, que causar una salida repentina sin ejecutar la expresin de iteracin.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 108 Observa este cdigo:
Al ejecutar este cdigo, se arroja en pantalla:
in for loop
El estamento imprime una vez, porque un return causa que se abandone la ejecucin no solo la iteracin sino que tambin todo el mtodo. As que la iteracin de la expresin nunca se ejecuta en este caso.
La siguiente tabla muestra el resultado de una salida forzada del bucle:
El for bsico: puntualizaciones
Ninguna de las tres secciones de la declaracin son obligatorias! El siguiente ejemplo es perfectamente vlido (aunque no es buena prctica):
En el ejemplo todas las partes estn vacas as que este bucle es infinito. Es importante saber que con la ausencia de la inicializacin y la seccin de incremento, el bucle actuar como bucle while. El siguiente ejemplo lo demuestra:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 109 El siguiente ejemplo demuestra que un bucle for con mltiples variables, y deben ser del mismo tipo. Recuerda que las variables declaradas en el estamento for son todas locales y no pueden ser usadas fuera del for.
La ultima cosa que aadir es que las tres secciones de for son independientes unas de otras. Las tres expresiones no necesitan operar la misma variable, aunque es lo tpico. Pero hasta el operador de iteracin, el cual es llamado errneamente el operador de incremento, no necesita incrementar o asignar nada, puedes poner un estamento virtual para lo que quieras que ocurra en cada iteracin del bucle. Mira lo siguiente:
Lo anterior imprime:
iterate iterate
11.5.1 El for mejorado (para arrays, for each) Fue introducido para Java 5 y est especializado en simplificar el trabajo de recorrer una coleccin o un array en un bucle. En este tema vamos a centrarnos en el uso de este nuevo for. Lo visitaremos nuevamente, cuando veamos las colecciones, que es donde esta nueva revisin se siente como en casa. En lugar de tener tres componentes, la versin actualizada tiene dos. Repasemos la vieja forma y luego usaremos la nueva:
Resultado:
12341234
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 110 Formalmente, vamos a describir cmo funciona:
Las dos piezas del estamento son:
declaracin: es un bloque recin declarado de una variable, de tipo compatible con los elementos del array al que se est accediendo. Esta variable estar disponible dentro del bloque, y su valor ser el mismo que el elemento actual del array.
expresin: debe evaluar el array que quieres recorrer. Podra ser un array, o un mtodo que devuelve un array. El array puede ser de cualquier tipo, objetos, primitivos o arrays de arrays. Usando las definiciones anteriores, echemos un vistazo a algunas declaraciones vlidas y no vlidas:
El for actualizado asume que salvo en una salida forzosa del bucle, siempre recorrers todos los elementos del array. El siguiente apartado de break y continue se aplican a los dos tipos de for.
11.6 El uso de break y continue
El uso de break y continue son usadas para parar todo el bucle o slo la iteracin actual (continue). Normalmente si usas break o continue, lo hars en una evaluacin if dentro del bucle, y si alguna condicin se convierte en true (o false dependiendo del programa) querrs salir inmediatamente. La diferencia entre ellos es si querrs continuar o no con la iteracin o saltar al primer estamento despus del bucle y continuar desde all
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 111 El estamento break hace que el programa detenga la ejecucin de su bucle inmediato y comienza a procesar la siguiente lnea de cdigo.
El estamento continue hace que slo la iteracin actual del bucle inmediato se detenga y comience por la siguiente evaluacin. Cuando usamos un continue en un bucle for, tienes que considerar los efectos que continue tiene en la operacin del bucle. Examina este ejemplo:
La pregunta es, esto es un bucle sin fin? La respuesta es no. Cuando llegamos al continue, la iteracin aun est ejecutndose. Se ejecuta a travs de la iteracin actual de manera natural. As que el ejemplo anterior, la variable i todava incrementar despus de que la condicin (i < 10) sea evaluada de nuevo. La mayora de las veces, un continue se usa dentro de un if tal como se muestra:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 112 Como nota personal, tengo que aadir que no vi claro el uso de continue, as que desarroll el siguiente cdigo:
As pude observar, que cuando la condicin se cumple, el resto del bloque no se ejecuta (se ignora cuando i==5), volviendo el punto de ejecucin del estamento for, donde se continua la iteracin hasta el final.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 113 11.6.1 Estamentos sin etiquetas
Los estamentos break y continue pueden estar etiquetados o no. Quizs lo ms comn es que no estn etiquetados. Como dijimos antes, un estamento break (sin etiqueta) saldr del ms inmediato bucle y seguir con la siguiente lnea de cdigo despus del cuerpo. El siguiente ejemplo demuestra un estamento break:
En este ejemplo, el estamento break esta sin etiquetar. El siguiente ejemplo es un ejemplo de continue etiquetado:
En este ejemplo, se est leyendo el campo de un fichero. Cuando encuentra un error, el programa salta al siguiente campo de la fila y usa el estamento continue para volver al bucle (sino es el final de la fila) y mantiene la lectura de varios campos. Si el estamento break se hubiera puesto en su lugar, el cdigo habra parado de leer al encontrar el error y se hubiera terminado la lectura del fichero.
El estamento continue es una manera de decir "Esta iteracin en particular necesita parar, pero no todo el conjunto. No quiera finalizar el resto de la iteracin".
11.6.2 Estamento con etiquetas
Aunque muchos estamentos en Java pueden ser etiquetados, lo ms comn es usar las etiquetas con bucles como for o while, en conjuncin con break y continue. Una etiqueta debe ser puesta justo antes del estamento etiquetado, y consiste en un identificador valido que finaliza con dos puntos (:).
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 114 Tienes que entender la diferencia entre etiquetado y sin etiquetar. La etiquetacin solo son necesarias en situaciones donde tienes un bucle anidado, y necesitas indicar cul de los bucles quieres romper, o a cul de ellos quieres continuar en la siguiente iteracin. Un estamento break saldr del bucle etiquetado, lo opuesto al bucle inmediato, si un break esta combinado con una etiqueta. Un ejemplo de como parece una etiqueta es lo siguiente:
La etiqueta debe de cumplir las mismas reglas que las variables en lo que se refiere al nombre. La sintaxis para el uso de la etiqueta en conjuncin con un estamento break es la palabra break , despus el nombre de la etiqueta, seguido de un punto y coma.
Un ejemplo ms completo es el que sigue:
El cdigo produce la siguiente salida:
Hello Good-Bye
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 115
En este ejemplo, la palabra Hello ser imprimida una vez. Luego la etiqueta de break ser ejecutada y el flujo saldr del bucle etiquetado outer. La siguiente lnea de cdigo imprimir Good-Bye. Veamos lo que pasa si el estamento continue se usa en lugar del break. El siguiente cdigo es similar al anterior, con la excepcin de la sustitucin de break por continue:
Al ejecutar el cdigo, se imprime:
Hello Hello Hello Hello Hello Good-Bye
En este ejemplo, Hello se imprimir cinco veces. Despus de que el estamento continue se haya ejecutado, el flujo continua con la siguiente iteracin del bucle identificado en al etiqueta. Finalmente, cuando la condicin en el bucle ms exterior se evala a false, este bucle terminara con la impresin de Good-Bye.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 116 12. Excepciones Una vieja mxima del desarrollo de software dice que del 80% del trabajo se usa un 20%. El 80% se refiere al esfuerzo para evaluar y manejar errores. En muchos lenguajes, escribir programas que evalen y manejan errores es tedioso e hincha el cdigo fuente de la aplicacin para hacerlo tan confuso como un espagueti. Aun as, la deteccin y manejo de errores debe ser el ingrediente ms importante para la robustez de una aplicacin. Java provee a los desarrolladores con elegantes mecanismos de manejo de errores que produce un eficiente y organizado cdigo: manejo de excepciones (exception handling). Las excepciones permiten a los desarrolladores detectar errores fcilmente sin escribir cdigo especial para evaluar valores de retorno. Incluso mejor, te permite manejar la excepcin de manera separada y transparente del cdigo generado por la excepcin. Tambin te permite usar el mismo manejador de excepciones para hacer frente a una serie de posibles excepciones.
12.1 El estamento try catch Antes de empezar, introduzcamos algo de terminologa. El termino excepcin significa condicin excepcional, y es un suceso que altera el fluido normal del programa. Un puado de cosas pueden conducir a una excepcin, incluyen fallo de hardware, fuente de recursos agotadas, y unos buenos bugs. Cuando ocurre un evento excepcional en Java, se dice que se ha arrojado una excepcin. El cdigo responsable de hacer excepciones se llama "manejador de excepciones" en ingls "exception handler", y atrapa la excepcin arrojada. El manejador de excepciones funciona transfiriendo la excepcin del programa al manejador de excepciones apropiado cuando sucede el evento. Por ejemplo, si llamas a un mtodo que abre una fila y la fila no puede ser abierta, la ejecucin del mtodo se detendr, y el cdigo que escribiste para manejar la situacin se ejecutara. Para ello, necesitamos una manera de decirle a la JVM que el cuando suceda una cierta excepcin, ejecute el cdigo. Para hacer esto usamos las palabras claves try y catch. El try se usa para definir un bloque de cdigo donde puede ocurrir la excepcin. Este bloque se le llama regin guardada (lo que significa que el cdigo peligroso va aqu). Una o ms clausulas catch especifican la excepcin (o grupo de excepciones, ms tarde veremos ms) a un bloque de cdigo que lo maneje. Aqu se muestra un ejemplo en pseudocdigo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 117
En este pseudocdigo, la lnea 2 hasta la 5 constituye la regin gobernada por try. La lnea 7 es el manejador de la excepcin de tipo MyFirstException. La lnea 12 es un manejador de excepciones de tipo MySecondException. Date cuenta de que el bloque catch sigue al try. Esto es obligatorio, si tienes uno o ms bloques catch, deben ir inmediatamente detrs de try. Adems, los bloques catch deben ir uno detrs del otro, sin estamentos o bloques de por medio. Tambin el orden de los catch importa, como veremos ms tarde. La ejecucin de la regin de seguridad empieza en la lnea 2. Si el programa se ejecuta sin excepciones, saltar a la lnea 15. Sin embargo, si la primera lnea 2 hasta la 5 arroja una excepcin de tipo MyFirstException, la ejecucin ser inmediatamente transferida a la lnea 7. Desde la lnea 8 a la 10 se ejecutarn todas las instrucciones del bloque, y luego la ejecucin continuara en la lnea 15 y continuar. Fjate que si una excepcin ocurre en la lnea 3 del bloque, el resto de lneas en el try no sern ejecutadas. Una vez que el control salte al bloque catch, no se volver a ejecutar el bloque try. Esto es exactamente lo que t quieres, creo... Imagina que tu cdigo se parece a esto en pseudo cdigo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 118 El pseudocdigo demuestra cmo funcionan normalmente las excepciones. El cdigo que depende de un riesgo en la operacin (como llenar una tabla con los datos de un fichero en internet) esta agrupado dentro del bloque try de tal manera que si, por ejemplo, la primera operacin fracasa, no vas a intentar continuar ejecutando otro cdigo que seguramente va a fallar tambin. El pseudocdigo del ejemplo no te va a dejar leer un fichero si no hay internet en primer lugar. Uno de los beneficios de usar un manejador de excepciones es que el cdigo para manejar en cualquier excepcin en particular puede ocurrir en la regin gobernada, necesite ser reescrita solo una vez. Volviendo a nuestro cdigo anterior, pueden haber tres sitios en nuestro bloque try que pueda generar una MyFirstException, pero si esto ocurre, ser manejado en el mismo bloque catch (lnea 7). Hablaremos de ms beneficios de la excepcin casi al final de este tema.
12.1.1 El uso de finally Aunque try y catch proveen de un fabuloso mecanismo para atrapar y manejar excepciones, nos queda el problema de como limpiar lo que deja una excepcin. Dado que la ejecucin dentro del bloque try se interrumpe sbitamente si hay una excepcin, no podemos limpiar el cdigo del bloque try y esperar que sea ejecutado. Casi que es una mala idea poner nuestro cdigo de limpieza en cada bloque catch, veamos el motivo. El manejador de excepciones no son el lugar adecuado para limpiar el bloque try porque cada manejador requiere su propia copia para limpiar el cdigo. Por ejemplo, si algn puerto o fichero se queda abierto en la regin de seguridad, cada excepcin debera cerrar ese fichero o ese puerto. Sera ms fcil olvidar la limpieza y tambin un montn de cdigo redundante. Para solucionar este problema, Java provee del bloque finally. El bloque finally encierra un cdigo que siempre ser ejecutado despus del bloque try, sin importar si hay una excepcin o no. Aunque hubiera un return al final del bloque try, se ejecutara justo despus del return, y antes de que el return se ejecute! Este es el lugar correcto para meter tu cdigo de limpieza, cerrar tus puertos o cerrar tus ficheros, etc... Si el cdigo se ejecuta sin excepciones, el cdigo finally se ejecutar inmediatamente despus. Veamos otro ejemplo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 119
Igual que antes, la ejecucin empieza en la primera lnea del bloque try, la lnea 2. Si no hay excepciones en el bloque try, la ejecucin prosigue por la lnea 11, la primera lnea del bloque finally. Por otra parte, si MySeconException arroja una excepcin mientras el bloque try se est ejecutando, la ejecucin prosigue en la primera lnea del manejador de excepciones, la lnea 8 de catch. Despus de que todo el cdigo en catch se haya ejecutado, el programa prosigue en la lnea 11, la primera lnea de finally. Repite despus de mi: el bloque finally siempre se ejecuta! OK, tenemos que afinar un poco, pero por ahora la idea de que finally siempre se ejecuta ha quedado clara. Tanto si se coge la excepcin, como si no, finally siempre se ejecuta. Ms adelante veremos unos pocos escenarios donde finally podra no completarse. Recuerda, la clusula finally no es obligatoria. Si no tienes, el cdigo, compilar perfectamente. De hecho, no todos los actos de un cdigo tienen que ser limpiados despus de que un bloque try se ejecute, as que la clusula finally no es obligatoria. Tambin, porque el compilador no exige tampoco la clusula catch, algunas veces querrs ejecutar el cdigo que tiene un try para terminar en el finally. Esta clase de programacin es til cuando la excepcin devuelve el flujo al mtodo que lo invoc, como explicaremos en la siguiente seccin. El uso de finally te permite limpiar el cdigo ejecutado aunque no haya clausula catch. Este cdigo muestra un try con finally pero sin catch:
Este cdigo muestra un try, catch y finally:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 120
El siguiente cdigo ilegal muestra un try sin catch o finally:
El siguiente cdigo ilegal muestra un ejemplo de cdigo fuera de lugar:
12.1.2 Programacin de excepciones no capturadas
Por qu los catch no son obligatorios? Que ocurre tras una excepcin en un bloque try donde no hay catch? No hay requerimientos para que en tu cdigo haya un catch para cada excepcin que pueda ser arrojada al correspondiente bloque try. El hecho, es que es dudoso que puedas hacer tal hazaa! Si un mtodo no provee de una clausula catch en particular, a ese mtodo se le llama "ducking" y lo que hace es pasarle la pelota a otro mtodo. As que, qu ocurre? Cuando un mtodo, llama a otro, y esto a otro... la ejecucin comienza, obviamente, por el ultimo mtodo invocado. Cuando uno de estos mtodos invocados tiene una excepcin, esta excepcin se recorre hacia atrs, esperando a ser atrapada. Si esta excepcin llega al primer mtodo, y no es atrapada, estalla deteniendo la ejecucin del programa.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 121
Observa este ejemplo donde se crea una clase main que ejecuta el mtodo reverse sin proporcionarle argumento con el que trabajar (lnea 8).
De la lnea 8 saltamos al mtodo reverse (lnea 23) que arroja una excepcin de tipo NadaQueDevolver. En la lnea 25, comprueba que la longitud de la cadena es menor que uno y arroja la excepcin.
En la lnea 41 se crea la clase NadaQueDevolver que hereda la clase Exception. El constructor de la clase hace una llamada (super) pasndole como parmetro un texto.
Volvemos a la lnea 10 donde se coge la excepcin y se imprime Excepcin arrojada: No hay texto que devolver.
Finalmente se ejecuta el bloque finally.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 122 12.1.3 Definiendo excepciones
Hemos discutido las excepciones como concepto. Sabemos que se arrojan cuando surge algn tipo de problema, y sabemos el efecto que tienen en el flujo de un programa. En esta seccin vamos a desarrollar los conceptos ms all y el uso de excepciones en cdigo Java funcional. Antes dijimos que una excepcin es una ocurrencia que altera el flujo normal del programa. Pero desde que estamos usando Java, cualquier cosa que no es un primitivo, es... un objeto. Las excepciones no, bien, esta es la excepcin que confirma la regla. Cada excepcin es una instancia de la clase Exception en su propio rbol de jerarqua. En otras palabras, las excepciones son siempre una subclase de java.lang.Exception.
Cuando se arroja una excepcin, un objeto del subtipo particular se instancia y maneja la excepcin como un argumento para la clusula catch.
Un catch se parece a esto:
En este ejemplo, es una instancia de la clase ArrayIndexOutOfBoundsException. Como cualquier otro objeto, puedes llamar a sus mtodos.
12.1.4 Jerarqua de las excepciones
Todas las clases de excepciones son subtipos de la clase Exception. Esta clase deriva de Throwable (la cual deriva de la clase Object). Esta imagen representa la jerarqua de las clases Exception:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 123 Como puedes observar, hay dos subclases que derivan de Throwable: Exception y Error. Las clases que derivan de Error representan situaciones inusuales que no son causadas por errores del programa, e indican cosas que normalmente no pasaran durante la ejecucin de un programa, como por ejemplo, que la JVM se quede sin memoria. Normalmente tu aplicacin no puede manejar este tipo de errores, as que no puede recuperarse. No se te pide que los manejes. Si tu cdigo no los maneja, (normalmente no) compilar sin problemas. Quizs hayas pensado en condiciones excepcionales, los errores tcnicamente no son excepciones porque no derivan de la clase Exception.
En general, una excepcin representa algo que ocurre como resultado no deseado por un error de programacin, ya que no se considera alguna condicin que pueda estar presente. Por ejemplo, si en tu aplicacin se supone que va a comunicarse con otra aplicacin en otro ordenador, y este, no contesta, esta excepcin no la causa un bug. Estas excepciones son un caso especial porque algunas veces indican error del programa. Tambin pueden presentarse casos raros para manejar excepciones en condiciones excepcionales. En tiempo de ejecucin, las excepciones son discutidas con gran detalle, ms adelante en este tema.
Java provee de muchas clases de excepciones, la mayora con nombres bastantes descriptivos. Hay dos maneras de conseguir la informacin de una excepcin. La primera es desde el tipo de excepcin en si misma. La siguiente es de la informacin que obtienes del objeto en excepcin. La clase Throwable (en lo alto de la herencia) provee a sus descendientes con algunos mtodos que son tiles para manejar las excepciones. Uno de ellos es printStackTrace(). Como imaginabas, puedes invocar los mtodos de una excepcin, como vimos en un ejemplo anterior, se imprimir el seguimiento de la excepcin.
Ya vimos que una llamada a la pila empieza desde abajo para terminar en el primer mtodo que invoco a los dems. Te dars cuenta de que printStackTrace() imprime la mayora de los mtodos recientes y luego continua descendiendo, imprimiendo el nombre de cada mtodo de la pila.
12.1.5 Manejando una clase completa de la jerarqua de excepciones
Ya hemos visto que la palabra clave catch te permite especificar un tipo en particular de excepcin. Puedes capturar ms de un tipo de excepciones en una nica clusula. Si la clase de excepcin especificada en catch no tiene subclases, entonces solo se atrapar esa excepcin en concreto. Sin embargo, si la clase especificada en catch tiene subclases, las subclases tambin sern atrapadas.
Por ejemplo, la clase IndexOutOfBoundsException (se da cuando el ndice especificado de un array sale de su rango) tiene dos subclases, ArrayIndexOutOfBoundsException y StringIndexOutOfBoundsException. Podras desear escribir un cdigo que maneje la excepcin, pero no sabes que excepcin se est arrojando (cual subclase). En este caso, puedes escribir un catch como este:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 124
Si cualquier cdigo en el bloque try arroja: ArrayIndexOutOfBoundsException o StringIndexOutOfBoundsException, la excepcin ser atrapada y manejada. Esto puede ser conveniente, pero podra ser usado por separado. Al especificar una excepcin de la superclase en la clusula catch, ests descartando informacin valiosa de tu excepcin. Puedes, naturalmente, averiguar como ocurri esa excepcin en la clase, pero si vas a hacer eso, es mejor escribir una clausula catch para cada tipo de excepcin.
Si tienes una jerarqua de excepciones compuesta de una superclase y un numero de subtipos, y ests interesado en manejar uno de los subtipos de una manera especial, necesitas escribir solo dos clausulas catch.
Cuando se arroja una excepcin, Java intentar encontrar la excepcin del tipo que encaje con la clusula catch. Si no la hubiese, entonces ir a por su supertipo. Si tampoco existiese, entonces se propagar la excepcin hasta que pueda ser manejada llegando a interrumpir la ejecucin del programa sino se detuviese.
Este proceso se le conoce como la excepcin que encaja con la bsqueda. Veamos un ejemplo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 125
Este programa intenta abrir un fichero para lectura de algn dato. Abrir y leer ficheros puede generar muchas excepciones, la mayora de ellas son de algn tipo de IOException. Imagina que en este programa estamos interesados en saber slo cuando hay una excepcin en concreto: FileNotFoundException . De otra manera no sabemos de que problema se trata.
FileNotFoundException es una subclase de IOException. As que podemos manejar en la clusula catch todos los subtipos de IOException, pero podramos evaluar la excepcin que determina si fue una FileNotFoundException . As que codificamos una excepcin exclusivamente para FileNotFoundException y separado de la excepcin que maneja los dems subtipos de excepcin.
Este cdigo generado para FileNotFoundException ser manejado por catch comenzando en la lnea 10. Si genera otra clase de IOException, a lo mejor, EOFException, que es subclase de IOException, ser manejado por el catch de la lnea 15. Si cualquier otra excepcin es generada, tal como excepciones en tiempo de ejecucin, no ser capturada y se propagara por la pila.
Date cuenta que la clusula para FileNotFoundException ha sido puesto antes que IOException. Esto es muy importante. Si no lo hiciramos, el programa no compilara. Los manejadores especficos de excepciones deben ser puestos delante siempre de los manejadores genricos. Lo siguiente no compilar:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 126
El compilador arrojara esto:
TestEx.java:15: exception java.io.FileNotFoundException has already been caught } catch (FileNotFoundException ex) { ^
12.1.6 Declaracin de Excepciones e Interfaces Pblicas
Como sabemos que mtodos que arrojan una excepcin y que podemos capturar? Un mtodo debe especificar el tipo y la cantidad de argumentos que acepta y lo que devuelve, las excepciones que un mtodo puede arrojar tienen que ser declaradas (al menos las excepciones son subclases de RunTimeException). La lista de excepciones declaradas es una parte de la interfaz pblica del mtodo. La palabra clave throws se usa para enumerar la lista de excepciones que un mtodo puede arrojar:
Este mtodo tiene un tipo de retorno void, no acepta argumentos y declara que puede arrojar dos tipos de excepciones: MyException1 y MyException2. Solo porque el mtodo declare que arroja excepciones, no quiere decir que siempre las est arrojando. Solo dice que podra.
Supn que tu mtodo no arroja directamente una excepcin, pero llama a un mtodo que lo hace. Puedes elegir manejar o no la excepcin. Si declaras la excepcin que tu mtodo puede conseguir de otro mtodo, y no provees de un try-catch, entonces el mtodo programar la excepcin.
Cualquier mtodo que pueda arrojar una excepcin (que sea subclase de RunTimeException) debe declarar la excepcin. Eso incluye mtodos que no estn arrojando excepciones directamente, pero estn pasando la excepcin a otro mtodo. Si pasas la excepcin, ests arrojando RunTimeException. Como las subclases estn exentas de implementarlo, el compilador no va a mirar si lo has hecho. Todas las excepciones RunTimeException son consideradas "comprobadas", porque el compilador lo hace para estar seguro de que has reconocido que algo malo podra pasar aqu.
Recuerda:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 127 Cada mtodo debe manejar todas las excepciones comprobadas suministrando un catch o listando mediante throws cada excepcin.
Esta regla es requerida en Java. Se la conoce como "manejar o declarar", algunas veces se la llama tambin "atrapar o declarar".
Nuevamente, algunas excepciones estn exentas de esta regla. Un objeto de tipo RunTimeException puede ser arrojado desde cualquier mtodo sin que se especifique como parte del mtodo o de la interfaz pblica (y no se necesita ningn try-catch). Incluso si un mtodo no declara RunTimeException , el mtodo que invoca tampoco tiene obligacin de declararlo o manejarlo. RunTimeException , Error, y todos sus subtipos de excepciones no comprobadas y esta clase de excepciones no tienen que ser manejadas. Por ejemplo:
Fjate en myMethod1(). Ya que EOException es subclase de IOException y este es de Exception, debe ser declarada como una excepcin que pueda arrojar este mtodo. Pero de donde viene la excepcin? La interfaz publica para el mtodo myMethod2() invocada aqu, declara que una excepcin de este tipo puede ser arrojada. Sin embargo ese mtodo actualmente arroja la excepcin por si misma o invoca otro mtodo que la arroja que no es importante para nosotros, lo nico que sabemos es que tenemos que atrapar la excepcin o declarar que se puede arrojar. El mtodo myMethod1() no atrapa la excepcin, as que la declara. Ahora veamos otro ejemplo valido:
De acuerdo con lo comentado, este mtodo puede arrojar un NullPointerException. Ya que RunTimeException es superclase de NullPointerException, y esto es una excepcin no comprobada, no necesita ser declarada. Podemos ver que myMethod3() no declara ninguna excepcin.
Las excepciones en tiempo de ejecucin son excepciones no comprobadas. Todas las dems excepciones son comprobadas, y no derivan de java.lang.RuntimeException. Una excepcin debe ser atrapada en alguna parte del cdigo. Si invocas un mtodo que arroja una excepcin pero no la atrapas, el cdigo no compilara. Eso es porque lo llamamos excepciones comprobadas, el compilador se asegura que son manejadas o declaradas.
Hay un gran nmero de mtodos en las libreras de Java 2 que arrojan excepciones, as que a menudo escribirs manejadores de excepciones para hacer frente a estas, generados por mtodos que ni tan siquiera escribiste.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 128 Tambin puedes arrojar excepciones t mismo, y la excepcin tambin puede ya existir en el API de Java, o uno creada por ti. Para crear tus propias excepciones, simplemente heredas Exception (o una de sus subclases) tal como sigue:
Este cdigo mosquear al compilador:
TestEx.java:6: unreported exception MyException; must be caught or declared to be thrown throw new MyException(); ^
Necesitas saber cmo se compara un Error con excepciones comprobadas y sin comprobar. Los objetos de tipo Error no son objetos Exception, aunque ellos presentan unas condiciones especiales. Exception y Error comparten la misma superclase, Throwable y ambas pueden ser arrojadas usando throws. Cuando un Error o una subclase de Error es lanzada, no se comprueba. No se le requiere atrapar objetos Error o subtipos. Tambin puedes lanzar errores t mismo (aunque aparte de una AssertionError no creo que quieras usar otra, quizs un OutOfMemoryError?) y puedes capturarla.
Lo siguiente compila perfectamente:
Si estuviramos lanzando una excepcin comprobada en lugar de un Error, entonces el mtodo doStuff() necesitara declarar la excepcin. Pero recuerda, los errores no son subtipos de Exception, no necesitan ser declarados. Si quieres declralos, pero al compilador le dar lo mismo quien o de donde sale un error.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 129 12.1.7 Relanzando la misma excepcin
Igual que puedes lanzar una nueva excepcin desde un catch, tambin puedes arrojar la misma excepcin que atrapas. Aqu la clusula catch lo hace:
Las dems clusulas catch asociadas con el mismo try sern ignoradas, si existiese un finally, se ejecutara y la excepcin volvera a ser arrojada desde el mtodo que lo invoc. Si lanzas una excepcin comprobada desde un catch, debes tambin declarar la excepcin! En otras palabras, debes manejar y declarar, lo opuesto a declarar o manejar. Lo siguiente es ilegal:
El mtodo doStuff() es quien claramente el que atrapa la excepcin IOException, pero el compilador va a decir, "si, muy bien, veo que atraparas la excepcin, pero no es suficiente. Si quieres relanzar la excepcin, tendrs que declararla".
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 130
En este programa se le pasa mediante parmetros la comida, y si no es del agrado, lanzar una excepcin.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 131 A continuacin expongo como lanzar una aplicacin con Eclipse adjuntando parmetros:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 132
y el ejemplo arroja como resultado:
No esta mal tu eleccion. Fin de la ejecucion.
Si ponemos otros manjares, como "piedras palos pelo" el programa arroja:
Esa comida no nos gusta! Fin de la ejecucion.
12.1.8 Definicin de conceptos, excepcin y error
Comencemos con la excepciones ms comunes, NullPointerException. Tal como vimos, esta excepcin ocurre cuando intentas acceder a un objeto usando una variable de referencia con el valor de null. No hay manera de que el compilador tenga la esperanza de encontrar este problema antes de ejecutar el programa (o sea, en tiempo de ejecucin). Veamos lo siguiente:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 133 Seguramente el compilador encontrara el problema en este programita! No, es cosa tuya. El cdigo compilara perfectamente y la JVM arrojara un NullPointerException cuando intente invocar el mtodo length().
Antes discutimos la llamada a la pila. Como recordars, usamos la convencin de que main() estara al final de la pila, y que como main() invoca otro mtodo, y ese mtodo invoca otro, etc... la pila crece. Naturalmente la pila reside en la memoria, e incluso si tu sistema operativo te da un 1GB de RAM para tu programa, la cantidad de memoria aun es finita. Es posible crecer la pila hasta ocupar toda la RAM de tu SO para guardar la pila. Cuando esto pasa, lo que obtienes es un (espera para verlo...), StackOverflowError. La manera ms comn para que esto ocurra es crear un mtodo recursivo. Un mtodo recursivo es aquel que se invoca as mismo en el cuerpo del mtodo. Mientras que eso puede sonar a locura, es una tcnica muy extendida para buscar y ordenar algoritmos. Mira este cdigo:
Como puedes ver, si cometes el error de invocar al mtodo go(), el programa caer en un agujero negro, go() invocara a go() hasta, no importa cuanta memoria tengas, que consigas un StackOverflowError. Nuevamente, solo la JVM sabe cuando esto ocurre, y la JVM ser la fuente de este error.
12.1.9 Programando el arrojo de excepciones
Fjate que digo "programando" como queriendo decir:
"Creado por una aplicacin y/o API por un desarrollador"
Por ejemplo, muchas clases en el API de Java tienen mtodos que toman cadenas como argumento, y convierten estas cadenas en nmeros primitivos. Un buen ejemplo de estas clases son llamadas clases de envoltorio.
Algunos programadores escribieron la clase java.lang.Integer y crearon mtodos como parseInt() y valueOf(). El sabio programador decidi que si a uno de estos mtodos le pasaba una cadena que no poda ser convertida en nmero, el mtodo arrojara un NumberFormatException. El cdigo parcialmente implementado se parece a esto:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 134 Otros ejemplos de excepciones programadas incluye una AssertionError (vale, no es una excepcin, pero se arroja programando), y arroja IllegalArgumentsException. El hecho, nuestro mtico desarrollador del API podra usar un IllegalArgumentsException para su parseInt(), pero devuelve NumberFormatException que hereda IllegalArgumentsException, y es un poco ms preciso, as, en este caso, usando NumberFormatException da soporte a la idea discutida antes: que cuando tienes una excepcin en una jerarqua, deberas usar la excepcin ms precisa que puedas.
Naturalmente como vimos antes, puedes hacer tus propias excepciones, y arrojarlas cuando quieras. Estas excepciones caseras tambin entran en la categora de excepciones programadas.
Excepciones ms comunes:
Excepcin Descripcin Arrojado por ArrayIndexOutOfBoundsException Arrojado cuando se intenta acceder a un array con un valor ndex equivocado (negativo o mayor que la longitud del array) JVM ClassCastException Arrojado cuando se intenta castear una variable de referencia de un tipo que no pasa el test ES-UN JVM IllegalArgumentException Arrojado cuando un mtodo recibe un argumento formateado de diferente manera que lo que espera el mtodo. Programado IllegalStateException Arrojado cuando el elemento de entorno no es el mismo que la operacin que se intenta hacer, por ejemplo un Scanner que ha sido cerrado. Programado NullPointerException Arrojado cuando se intenta acceder a un objeto con una variable de referencia null. JVM NumberFormatException Arrojado cuando un mtodo que convierte una cadena a un nmero, recibe una cadena que no puede ser convertida. Programado AssertionError Arrojado cuando el test booleano devuelve falso. JVM ExceptionInInitializerError Arrojado cuando se intenta inicializar una variable esttica o un bloque. JVM StackOverflowError Se arroja cuando un mtodo se recurre profundamente. Cada invocacin se aade a la pila. JVM NoClassDefFoundError Arrojado cuando la JVM no encuentra la clase que necesita por un error en la lnea de comando, un problema de classpath o falta una .class. JVM
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 135 12.2 Mecanismo de aserciones
Sabes que no debes hacer suposiciones, pero no puedes evitarlo cuando estas escribiendo cdigo. Lo haces ponindolos en comentarios:
Escribes estamentos con ellos:
Aadido al lenguaje Java 1.4, las aserciones te permiten comprobar supuestos durante el desarrollo, sin el gasto (tu tiempo) de escribir manejadores de excepciones que asumes que nunca pasaran una vez el programa este desarrollado.
Se supone que asumes que un nmero pasado como parmetro a un mtodo nunca ser negativo. Mientras compruebas y limpias de errores el cdigo, quieres validar tu suposicin, pero no quieres tener que empezar a escribir excepciones o cdigo evaluando cuando ya has hecho el programa. Pero dejar esto sin comprobar es un riesgo. Aserciones al recate! Mira este cdigo:
Ya que supones que ests en lo cierto, no quieres emplear ms tiempo para escribir excepciones. Y en tiempo de ejecucin no quieres incluir ms if-else porque alcanzar el else significa que tu lgica (lo que fuera que estaba ejecutndose antes de que este mtodo fuera invocado) ha fallado.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 136 Las aserciones te permiten comprobar tus suposiciones durante el desarrollo, pero el cdigo de la asercin bsicamente se evapora cuando el programa est finalizado, dejando atrs el cdigo debugger (depurador) y borrndolo. Escribamos un mtodo para evaluar que el argumento no daba negativo:
No slo el hacer aserciones te permite dejar tu cdigo ms legible, ya que las aserciones estn inactivas a menos que las actives, entonces, el cdigo de arriba cuando lo compiles, quedara como:
El funcionamiento de las aserciones es bastante simple. La asercin dar siempre true, si no, problema! El cdigo continua ejecutndose. Pero si tu asercin no est desactivada y da falso, entonces una excepcin tipo "que se pare el mundo" AssertionError se lanza (algo que jams podrs manejar) entonces, puedes arreglar la lgica que te condujo a este problema.
Las aserciones vienen en dos sabores: realmente simple, y simple, como por ejemplo:
y
La diferencia entre los dos es que la versin simple aade una segunda expresin, separado del primero (expresin booleana) por dos puntos, esta expresin de cadena se aade al Stack trace (es el sistema que cuando salta un error, te muestra el recorrido del error). Ambas versiones arrojan inmediatamente AssertionError, pero la versin simple te da una ayuda para depurar el cdigo, mientras que la otra versin, solo te dice que tu lgica ha fallado.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 137 12.2.1 Reglas de expresin de las aserciones
Las aserciones pueden tener una o dos expresiones, dependiendo de si usas el modo simple, o el realmente simple. La primera expresin debe dar siempre un valor booleano! Sigue las mismas reglas que para el if. Todo lo que hace una asercin es una evaluacin, lo que significa que el resultado slo puede ser verdadero o falso. Si es verdadero, no hay problema. Sino, entonces tu suposicin era errnea y consigues un AssertionError.
La segunda expresin, solo se usa con el modo simple, que puede ser cualquier cosa que resulte en un valor. Recuerda, la segunda expresin se usa para generar un mensaje de texto que muestre en el Stack trace algo ms de informacin para depurar el cdigo. Funciona como System.out.println() en el que puedes pasarle un primitivo o un objeto, y lo convertir a cadena de texto. Debe devolver un valor!
Lo siguiente muestra una lista de expresiones vlidas y errneas para ambas clases de aserciones, recuerda que la expresin 2 se usa slo con el modo simple, donde la segunda expresin solo te da un poco ms de informacin sobre el detalle de la asercin:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 138 12.2.2 Aserciones, identificados o palabra clave
Si quieres usar aserciones, tienes que pensar primero como compilar con aserciones tu cdigo, y entonces, pensar como ejecutar el programa con las aserciones activadas. Ambas requieren Java 1.4 o superior, que nos trae el primer punto, como compilar con aserciones en tu cdigo.
Identificadores contra palabras claves
Antes de la versin 1.4, tendras que haber escrito:
Fjate que en el cdigo, asercin se usa como un identificador. Esto ya no es un problema en el 1.4. Pero no puedes usar palabras claves o reservadas como identificadores, empezando con assert que es una palabra clave. El dato de esta cuestin es que puedes usar assert como palabra clave o como un identificador, pero no como ambas.
El uso de javac (Compilador de Java) con assert
El compilador de Java usar siempre assert como palabra clave por defecto. A menos que le digas lo contrario, el compilador generar un error si encuentra la palabra assert usada como identificador. Sin embargo, puedes decirle al compilador que le estas dando una cdigo antiguo y que quisieras que lo compilase a la antigua usanza. Digamos que haces un arreglo a un viejo cdigo del 1.3 que usa assert como identificador. En la lnea de comandos podras escribir:
El compilador mostrara mensajes cuando descubra que la palabra assert se usa como identificador, pero el cdigo compilar y se ejecutara. Supn que le dices al compilador que tu cdigo es de la versin 1.4 o posterior, por ejemplo:
En este caso el compilador mostrar errores cuando descubra que estas usando assert como un identificador.
Si quieres decirle al compilador que use las reglas de Java 5 puedes hacer una de estas tres cosas:
Omitir la opcin -source la cual est por defecto, o aadir una de estas dos opciones a source:
Te das cuenta lo claro que es Sun sobre 1.5 y 5?
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 139 Si quieres usar aserciones como identificadores en tu cdigo, debes compilar usando -source 1.3. La siguiente tabla resume como el compilador de Java 5 reacciona a assert como identificador o palabra clave:
12.2.3 Ejecucin con aserciones
Aqu tenemos algo bueno. Una vez que has escrito tu cdigo con aserciones puedes elegir entre activarlas o no en tiempo de ejecucin! Recuerda que las aserciones estn desactivadas por defecto.
Activas las aserciones en tiempo de ejecucin usando:
o
Enable significa activar, as que "enableassertions" es "activar aserciones". En eclipse, los parmetros se introducen en este men:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 140
Tambin tienes que conocer la lnea de comandos para desactivar las aserciones:
o
12.2.4 Selector para activar y desactivar los assert
La lnea de comando para aserciones puede ser usada de diferentes maneras: Sin argumentos (como en el ejemplo), que activa o desactiva las aserciones en todas las clases, excepto para las clases del sistema. Con el nombre de un paquete, de esta manera se especifica el paquete donde quieres que acte (o no) la asercin. Con el nombre de la clase, al igual que con el nombre del paquete.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 141 Puedes combinar los interruptores para decirle que active las aserciones en una clase y que no se activen en las dems, tal como:
Esta lnea de comando le dice a la JVM que active las aserciones para todo el programa excepto para la clase en com.geeksanonymous.Foo. Puedes seleccionar todo el paquete haciendo:
Esta lnea le dice a la JVM que active las aserciones, pero que las desactive en el paquete com.geeksanonymous y todos sus subpaquetes. Puede que el trmino de subpaquetes no te sea familiar, ya que no hemos hablado de ellos. Un subpaquete es un paquete en un directorio del paquete nombrado. Por ejemplo:
El subpaquete de com.geeksanonymous es el paquete twelvesteps. Recuerda que en Java el com.geeksanonymous.twelvesteps se trata como un paquete distinto y que no tiene relacin con los paquetes que hay por encima de el, tan slo estn compartiendo directorio. La siguiente tabla muestra ejemplos para activar o desactivar aserciones en la lnea de comandos:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 142 12.2.5 El uso apropiado para las aserciones
No todos los usos vlidos de las aserciones se consideran de uso apropiado.
Como ocurre con gran parte de Java, se puede abusar del uso de las aserciones a pesar de los esfuerzos de los ingenieros para disuadir de hacer esto. Por ejemplo, nunca te harn manejar una asercin que falle. Esto quiere decir que no deberas atraparla con catch para intentar manejarla. Legalmente, sin embargo, AssertionError es subclase de Throwable, asi que puede ser atrapado. Pero no lo hagas!! Si intentas recuperar algo, debera ser una excepcin. Para disuadirte de que sustituyas una asercin de una excepcin, el AssertionError no te da acceso al objeto que lo gener. Todo lo que consigues en un mensaje de texto.
No use las aserciones para validar argumentos de un mtodo pblico
Esto es un ejemplo de uso inapropiado:
Un mtodo pblico puede ser invocado desde cdigo que no controlas (o desde un cdigo que jams has visto). Ya que los mtodos pblicos son parte de tu interface al mundo exterior, se supone que tienes que garantizar cualquier anomala en los argumentos que el mtodo sea forzado a tomar. Pero las aserciones no garantizan que se ejecuten (normalmente se desactivan en las aplicaciones), el cdigo no se ejecutara si las aserciones estn desactivadas. No quieres cdigo accesible que funcione solo condicionalmente, dependiendo de si las aserciones estn activadas.
Si necesitas validar los argumentos de un mtodo pblico, probablemente arrojars excepciones, es decir IllegalArgumentException, si el valor pasado al mtodo pblico no es vlido.
Usar aserciones para validar argumentos en un mtodo privado
Si escribes un mtodo privado, seguramente escribirs algn cdigo que lo ejecute. Cuando asumes que la lgica del cdigo es correcta, puedes evaluar la suposicin con una asercin de esta manera:
La nica diferencia importante entre en el ejemplo anterior y este, es el modificador de acceso. As, puedes forzar a cumplir las condiciones en los mtodos privados, pero no en los mtodos pblicos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 143
No uses aserciones para validar una lnea de comando tomada como argumento
Esto es realmente un caso especial. Si tu programa requiere una lnea de comandos de argumentos, necesitars usar excepciones.
No uses aserciones en mtodos pblicos para evaluar casos que sabes que nunca podran suceder.
Esto incluye bloque de cdigo que nunca podra ser ledo, incluyendo el default de un bloque switch como este:
Si asumes que un cdigo en particular podra no ser ejecutado, como en el ejemplo donde hay una asercin, entonces podras obtener un falso error porque este cdigo nunca sera ejecutado.
No uses una asercin en expresiones que puedan causar efectos colaterales!
Esto podra ser muy mala idea:
la regla es, una asercin dejara el programa en el mismo estado que estaba antes de la expresin! Piensa en ello. Las aserciones no garantizan que se ejecuten siempre, as que si no quieres que tu cdigo tenga un comportamiento distinto dependiendo de si las aserciones estn activadas, las aserciones no deben causar algn efecto.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 144 13.1 La clase String
La clave del objeto String, es que una vez creado, no puede ser cambiado, as que, que es lo que realmente ocurre cuando un objeto String parece que ha cambiado?
Los objetos String inmutables
Empezaremos con un poco de informacin de trasfondo sobre las cadenas. El manejo de caracteres es un aspecto muy fundamental en la mayora de los lenguajes de programacin. En Java, cada carcter en una cadena es un carcter Unicode de 16 bits. Ya que los caracteres Unicode son de 16 bits (no los escasos 7 u 8 bits que ASCII provee), el alfabeto internacional de caracteres se representa como Unicode.
En Java, las cadenas son objetos. Al igual que cualquier objeto, puedes instanciar una cadena con new:
Esta lnea de cdigo crea un nuevo objeto de la clase String, y le asigna la variable de referencia s. Hasta ahora, los objetos String se parecen a cualquier otro objeto. Ahora asignemos una cadena como valor:
Tal como esperabas la clase String tiene un buen puado de constructores, as que puedes usar el atajo que ms te convenga:
y ya que usars cadenas todo el tiempo, incluso puedes hacer esto:
Hay algunas diferencias entre estas opciones, que veremos ms tarde, pero todas tienen en comn que crean un nuevo objeto String, con el valor abcdef y se le asigna la variable de referencia s. Ahora digamos que quieres una segunda referencia a un objeto String al que se refiere s:
Todo bien hasta ahora. Los objetos String parece que se comportan de la misma manera que los dems objetos, as que, cual es la pega?... La inmutabilidad! (Y qu diablos es la inmutabilidad?) Una vez que has asignado un valor a String, el valor nunca cambia, es inmutable, no cede. (Hablaremos de esto ms tarde.) Las buenas noticias es que mientras un objeto String es inmutable, su referencia no, as que continuamos con nuestro anterior ejemplo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 145 Ahora espera un minuto, dijimos que era inmutable? Que es lo que pasa con "aadir un literal al final de la cadena?" Excelente pregunta, veamos que ha pasado realmente... La JVM tom el valor del objeto s y aadi el literal al final, dndonos el valor "abcdef mas cosas". Ya que las cadenas son inmutables, la VM no puede dar este nuevo valor a la variable de referencia as que lo que hace es reasignar la variable de referencia al nuevo valor. Llegados a este punto hay dos objetos de cadena creados, el antiguo y el nuevo. Tcnicamente son tres porque el literal para concatenar es otra cadena nueva. Pero slo tenemos referencias a "abcdef" y "abcdef mas cosas" (referenciado ahora por s). Que pasa sino tenamos previsto crear una segunda variable de referencia para "abcdef" antes de que concatenramos " mas cosas"? En este caso, la cadena original aun estar en memoria pero se la considera "perdida". Ningn cdigo de nuestro programa tiene alguna manera de referenciarla. Acurdate de que la cadena original, es inmutable, as que no ha cambiado, lo que si ha cambiado es la referencia de la variable s. Otro ejemplo:
ahora:
otro:
Como ves, el uso del mtodo sobre la referencia no implica que la antigua referencia se pierda, al contrario, si la nueva cadena no es referenciada, es la que se pierde. La discusin que sigue contiene las claves de la inmutabilidad de las cadenas de Java. Cubriremos ms detalle de la clase String, pero no te equivoques, lo que hemos cubierto est lejos de ser la parte ms importante para entender cmo funcionan los objetos String en Java. Terminaremos esta seccin representando un ejemplo de pregunta endiablada. Toma tu tiempo para escribir en una hoja el resultado de lo siguiente:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 146
Cul sera la salida? Cuantas variables de referencia hay? Cuantos objetos String fueron creados antes de la salida? Respuesta: El resultado es "spring winter spring summer". Hay dos variables de referencia, s1 y s2. Haba en total ocho objetos creados: "spring", "summer" (se pierde), "spring summer" (se pierde), "spring fall" (se pierde), "spring summer spring" (se pierde), "winter" (se pierde), "spring winter" (spring se pierde aqu). Solo dos de los ocho objetos String no se pierden en este proceso.
13.1.1 String y memoria En esta seccin vamos a ver como Java maneja los objetos String en memoria, y algunas de las razones que dan a lugar a este comportamiento. Una de las claves de cualquier buen programador es hacer un eficiente uso de la memoria. Ya que la aplicacin crece, es normal que las cadenas literales ocupen grandes cantidades de memoria y a menudo son redundantes en el universo de cadenas literales del programa. Para hacer ms eficiente el uso de la memoria, la JVM tiene un rea especial de memoria llamada "Piscina de constantes de String". Cuando el compilador encuentra un String literal, verifica que en la piscina exista otra idntica. Si existe, la referencia al nuevo literal es dirigida a la ya existente, no a la nueva creada. Ahora podemos empezar a ver por qu hacer a los objetos String inmutables es una buena idea. Si hay varias variables de referencia apuntando a la misma cadena aun sin saberlo, no sera buena idea cambiar el valor de la cadena. Ahora puedes pensar "Bien eso est bien, pero que pasa si alguien sobrescribe la clase String, no podra causar eso un error en la pool?" Esa es una de las principales razones por la que la clase String es marcada como final, nadie puede sobrescribir el comportamiento de ninguno de los mtodos de String, as que puedes estar tranquilo que los objetos inmutables, sern, inmutables. Veamos un par de ejemplos de cmo se puede crear un String, y asumamos que no existen ms objetos en la pool:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 147 En este caso, "abc" ira a la pool y s lo referenciara.
En este caso, ya que usamos new, Java crear una nueva cadena en la memoria normal (no en la pool), y s la referenciar. Adems, "abc" ira a la pool.
13.1.2 Mtodos importantes de la clase String Los siguientes mtodos son algunos de los ms comunes usados en la clase String: charAt() Devuelve el carcter localizado en el ndice especificado. concat() Concatena una cadena con el final de la otra (lo mismo que "a"+"b"). equalIgnoreCase() Determina la igualdad de dos cadenas ignorando las maysculas. length() Devuelve el nmero de caracteres en una cadena. replace() Reemplaza las concurrencias de un carcter con otro carcter. substring() Devuelve una parte de la cadena. toLowerCase() Devuelve una cadena con los caracteres en minsculas. toString() Devuelve el valor en forma de cadena. toUpperCase() El opuesto a toLowerCase(). trim() Elimina los espacios de una cadena. Veremos los metodos en detalle.
public char charAt(int index) Este mtodo devuelve el carcter localizado en el ndice especificado. Recuerda, el primer ndice es el cero.
public String concat(String s) Este mtodo devuelve una cadena con el valor del parmetro aadido al final de la cadena.
Los operadores + y += funcionan de forma similar:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 148
En el ejemplo "atlantic ocean", tienes que darte cuenta del valor de x, ha cambiado. Recuerda que la operacin += es de asignacin, as que realmente est creando la nueva cadena "Atlantic ocean" y asignndole la variable x, quedando "Atlantic" abandonada.
public boolean equalsIgnoreCase(String s) Este mtodo devuelve un valor booleano (true o false) dependiendo de si el valor de la cadena es igual al del mtodo. Este mtodo devolver true aunque los caracteres sean capitales. Ejemplo:
public int length() Este mtodo devuelve la longitud de la cadena usada para invocar el mtodo, ejemplo:
public String replace(char old, char new) Este mtodo devuelve una cadena cuyo valor es la cadena invocada en el mtodo actualizando la concurrencia. Donde el primer carcter ser reemplazado por el segundo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 149 public String substring(int begin) public String substring(int begin, int end) Este mtodo devuelve una parte de la cadena suministrada. El primer argumento representa la localizacin (la primera letra ocupa el ndice cero) de la subcadena. Si la llamada tiene solo un argumento, la subcadena se extraer hasta el final de la cadena original. Si tiene dos argumentos, la subcadena terminara en el carcter localizado en esa posicin.
Ejemplo:
public String toLowerCase() Este mtodo devuelve una cadena cuyo valor es la cadena usada para invocar el mtodo, pero con todas las letras maysculas convertidas a minsculas. Por ejemplo:
public String toString() Este mtodo devuelve el valor de la cadena usada para invocar el mtodo. Qu? Para que iba yo a necesitar tal cosa? Un mtodo que no hace nada? Todos los objetos en Java tienen un mtodo toString(), que devuelve una cadena significativa que describe el objeto en cuestin. En caso de una cadena, que ms significativo podra ser que el mismo valor de la cadena? Para ms inri, un ejemplo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 150 public String toUpperCase() Este mtodo devuelve una cadena cuyo valor es la cadena usada para invocar al mtodo, pero todos los caracteres en minsculas los devuelve en maysculas. Por ejemplo:
public String trim() Este mtodo devuelve una cadena cuyo valor es la cadena usada para invocar el mtodo, pero los espacios en blanco son eliminados. Ejemplo:
13.2 StringBuffer y StringBuilder Las clases java.lang.StringBuffer y java.lang.StringBuilder se usan cuando tienes que hacer un montn de modificaciones a una cadena de caracteres. Tal como vimos antes, las cadenas son objetos inmutables, si eliges hacer un montn de manipulaciones con objetos de cadena, terminars con un montn de objetos perdidos en la pool de String. (Incluso en estos das de los gigabytes de RAM, no es buena idea desperdiciar la memoria en objetos descartados). Por otra parte, los objetos del tipo StringBuffer y StringBuilder pueden ser modificado tantas veces como quieras sin dejar por detrs ese rastro de objetos descartados. StringBuffer vs StringBuilder La clase StringBuilder fue aadida en Java 5. Tiene el mismo API que StringBuffer, excepto que StringBuilder no es un hilo seguro. En otras palabras, sus mtodos no estn sincronizados. Sun recomienda que uses StringBuilder en lugar de StringBuffer cuando sea posible porque StringBuilder se ejecuta ms rpido. As que aparte de la sincronizacin, cualquier cosa que digamos sobre los mtodos de StringBuilder valdr para StringBuffer y viceversa.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 151 El uso de StringBuilder y StringBuffer Hemos visto que en el examen se te va a evaluar la compresin sobre la inmutabilidad de String en fragmentos como este:
Conseguimos una nueva cadena, pero en trasfondo, la cadena "abc" ha quedado perdida en la pool de String, malgastando memoria. Si hubiera usado un StringBuffer en lugar de String, seria:
Todos los mtodos de StringBuffer que discutiremos operan sobre el valor de StringBuffer invocado del mtodo. As que una llamada a sb.append("def"); est aadiendo "def" a si mismo. En efecto, estos mtodos pueden ser encadenados unos con otros:
Date cuenta que en los dos ejemplos anteriores, haba solo una llamada a new, y en cada ejemplo no se han creado objetos extras. Cada ejemplo necesitaba solo una lnea StringXxx para ejecutarse.
13.2.1 Mtodos importantes de las clases StringBuffer y StringBuilder Los siguientes mtodos devuelven un objeto StringXxx con el valor del argumento aadido al valor del objeto que invoca el mtodo.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 152 public synchronized StringBuffer append(String s) Como vimos antes, este mtodo actualizar el valor del objeto que invoc el mtodo, dependiendo de si se le asigna una variable al retorno. Este mtodo toma muchos argumentos, incluyendo boolean, char, float, int, long y otros.
public StringBuilder delete(int start, int end) Este mtodo devuelve un objeto StringBuilder y actualiza el valor del objeto StringBuilder que invoc la llamada al mtodo. En ambos casos, se elimina una subcadena del objeto original. El ndice inicial (el primero es el cero) se define en el primer argumento y el ndice final (el primero tiene que ser al menos el 1!) es definido en el segundo argumento. Estudia detenidamente este ejemplo:
public StringBuilder insert(int offset, String s) Este mtodo devuelve un objeto StringBuilder y actualiza el valor del objeto que invoc la llamada del mtodo. En ambos casos, la cadena pasada en el segundo argumento se inserta dentro del original StringBuilder comenzando en la localizacin offset representado en el primer argumento (el primero es el cero). Tambin, como segundo argumento puede tomar cualquier tipo de dato, boolean, char, double, float, int, long...etc... pero es el tipo cadena lo que ms vas a ver:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 153 public synchronized StringBuffer reverse() Este mtodo devuelve un objeto StringBuffer y actualiza el valor del objeto que invoc la llamada del mtodo. En ambos casos, la cadena en StringBuffer es invertida, el primer carcter se convierte en el ltimo:
public String toString() Este mtodo devuelve el valor del objeto StringBuffer que invoco al mtodo como una cadena:
Esto es todo para StringBuffer y StringBuilder. Recuerda que al contrario de los objetos String, StringBuffer y StringBuilder si mutan.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 154 14.1 Resumen de las clases I/O
File Este API dice que la clase File es una representacin abstracta de un fichero y el nombre de su ruta. La clase File no se usa para leer o escribir datos, se usa para trabajar a alto nivel, creando ficheros vacos, buscando ficheros, borrando, creando directorios y trabajando con rutas. FileReader Esta clase se usa para leer caracteres de un fichero. El mtodo read() es de bajo nivel, y te permite leer un solo carcter, de toda la cadena de caracteres, o un nmero fijo de caracteres. Los FileReader se usan para envolver objetos de alto nivel, como BufferedReader, que dan ms rendimiento y proveen de formas ms convenientes para trabajar con datos. BufferedReader Esta clase se usa para crear clases Reader de bajo nivel como FileReader, ms eficientes y fciles de usar. Comparado a los FileReader, BufferedReader es capaz de leer grandes cantidades de datos de una sola vez y ocuparlos en un buffer. Cuando te preguntes por el siguiente carcter o lnea de datos, se toma desde el buffer, que minimiza el nmero de veces de operaciones de lectura. Adems, BufferedReader te provee de ms eficientes mtodos tales como readLine(), que te permiten leer la siguiente lnea de caracteres de un fichero. FileWritter Esta clase se usa para escribir caracteres a un fichero. Su mtodo write() te permite escribir caracteres o cadenas a un fichero. Los FileWriter son, normalmente, envoltorios para objetos de alto nivel de tipo Writer, tales como BufferedWriter o PrintWriter, que proveen de mejor rendimiento y son de alto nivel, con mtodo ms flexibles para escribir datos. BufferedWriter Esta clase se usa para crear clases de bajo nivel como FileWriter, mas eficiente y fcil de usar. Comparado a FileWriter, BufferedWriter escriben grandes cantidades de datos en un fichero de una sola vez, minimizando el nmero de veces, que retrasa, las operaciones de escritura. Adems, la clase BufferedWriter provee del mtodo newLine() que hace ms fcil crear plataformas especficas que separan las lneas automticamente. PrintWriter Esta clase ha sido mejorada significativamente en Java 5. Ya que los nuevos mtodo y constructores creados (como PrintWriter con File o String), puedes encontrar que puedes usar PrintWriter en sitios donde antes necesitaras un Writer envuelto con FileWriter y/o un BufferedWriter. Nuevos mtodo como format(), printf() y append() hacen de PrintWriter una clase muy flexible y poderosa.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 155 14.2 Creando ficheros, el uso de la clase File Los objetos del tipo File se usan para representar el fichero actual (pero no los datos que contiene) o directorios que existen en el disco fsico de la computadora. Comencemos con unos pocos ejemplos de creacin de ficheros, escribirlos y leerlos. Primero, crearemos un fichero y escribiremos unas lneas en el:
Si ejecutas este programa, cuando mires el contenido de tu directorio actual, descubrirs que no hay absolutamente ninguna indicacin de algn fichero llamado fileWrite1.txt. Cuando creas una instancia de File, no estas creando el fichero, slo el nombre. Una vez que tengas el objeto File, hay varias maneras para crear el fichero. Veamos lo que puede hacerse con el objeto File:
Esto da como salida:
false true true
Y tambin produce un fichero vaco en tu directorio. Si ejecutas el cdigo una segunda vez, se mostrar:
true false true
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 156 Examinemos las ejecuciones: Primera ejecucin: La primera llamada a exists() devuelve false, lo que esperbamos, recuerda, que new File() no crea un fichero en el disco! El mtodo createNewFile() crea el fichero, y devuelve true, indicando que ha sido creado un nuevo fichero, y que no exista antes. Finalmente, llamamos a exists() otra vez, y esta vez devuelve true, indicando que el fichero ya existe en el disco.
Segunda ejecucin: La primera llamada a exists() devuelve true porque nosotros hemos creado el fichero en la primera ejecucin. Luego la llamada a createNewFile() devuelve false ya que el mtodo no cre el fichero esta vez. Naturalmente la ltima llamada a exists() devuelve true. Un par de cosas nuevas han pasado en este cdigo. Lo primero, fjate que tuvimos que poner nuestro fichero en un try-catch. Esto es as para todos los cdigos I/O que escribes. I/O es una de esas clases con riesgos inherentes. Seamos simples por ahora, e ignoremos las excepciones, pero aun necesitaremos seguir manejando o declarando la regla para la mayora de los mtodo I/O que declaren excepciones marcadas. Hablaremos ms sobre I/O. Usamos un par de mtodo de la clase File en este cdigo: boolean exists(), este mtodo devuelve true si puede encontrar el fichero. boolean createNewFile(), este mtodo crea un nuevo fichero si no existe an.
14.3 El uso de FileWriter y FileReader En la prctica, lo ms probable es que no uses FileWriter y FileReader sin envoltorio (en breve se explica mas). Como dije antes, vayamos y hagamos un pequeo fichero I/O:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 157
lo que produce la salida: 12 howdy folks Lo que ha pasado: FileWriter fw = new FileWriter(file) hizo estas tres cosas: 1. Se cre una variable de referencia fw de tipo FileWriter. 2. Se cre un objeto FileWriter y se asign a fw. 3. Se cre un fichero vaco en el disco (puedes comprobarlo).
Escribimos 12 caracteres en el fichero con write(), y luego hizimos flush() y close().
Hicimos un objeto FileReader, que abri el fichero para lectura.
El metodo read() ley todo el fichero, un carcter cada vez, y ponerlo dentro de char[].
Imprimimos el nmero de caracteres ledos, e hicimos un bucle en el array para imprimir cada carcter, luego, cerramos el fichero. Antes de seguir, hablemos sobre flush() y close(). Cuando escribes un dato en una cadena, pueden ocurrir un montn de cosas en el bfer, y nunca sabrs exactamente cundo se envi el ltimo dato. Podras ejecutar muchas operaciones de escritura en una cadena antes de cerrarla. Al invocar el mtodo flush() antes de cerrar el fichero, te garantiza que el ltimo dato se ha escrito en el fichero.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 158 No importa cmo ests usando un fichero. Para lectura o escritura, tienes que invocar el mtodo close(). Cuando ests trabajando con ficheros I/O, ests usando una gran cantidad de recursos del sistema, as que cerrar el fichero liberar las tareas del sistema. Por mi cuenta he practicado un poco lo dicho aqu, porque no soy persona de estudiar de memoria, sino de comprender y asociar, y sin estudiar, continuar el temario es como leer y tener la cabeza ocupada en coches y motos, terminas el libro y no te has enterado de nada, as que all voy. Para empezar, acabo de acordarme, que sino inicializas el array, arroja un NullPointerException. Pensaba que se inicializara como lo hace PHP, automticamente dependiendo de la entrada. Pues no. Confirmado. Luego, qu ocurre si declaras un array de 50 bytes y solo ocupas una parte? Bien, este fue el cdigo que hice:
y este fue el resultado:
Podras haber querido experimentar y darte cuenta que al usar read() sin variable, el cdigo no lanza error, pero, sin una variable que haga referencia al contenido ledo, como lograras tener acceso a esta informacin, donde est, quien lo sabe?
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 159 Ahora, volviendo a nuestro ltimo ejemplo del manual. Este programa en realidad, funciona, pero hay un par de cosas dolorosas: 1. Cuando ests escribiendo datos a un fichero, insertamos manualmente los operadores de salto de carro (en nuestro caso \n).
2. Cuando leemos los datos, los ponemos en un array. Al estar en un array, tuvimos que declarar su tamao por adelantado, as que tendramos un problema si no supiramos el tamao. Podimos leer los datos de carcter en carcter, buscando el final despus de cada read(), pero es bastante doloroso tambin. Por estas limitaciones, nosotros usamos clases de ms alto nivel, como BufferedWriter o BufferedReader en combinacin con FileWriter o FileReader.
14.4 Combinando clases I/O, BufferedWriter y BufferedReader Todo el sistema I/O de Java fue diseado con la idea de usar varias clases en combinacin. Combinar las clases I/O se le llama envolviendo clases y otras veces, encadenando clases. El paquete I/O de Java tiene ms o menos 50 clases,10 interfaces, y 10 excepciones. Cada clase en el paquete tiene un propsito especfico (creando una alta cohesin) y estn diseadas para ser combinadas unas con otras de incontables maneras para manejar una amplia variedad de situaciones. Cuando llega la hora de hacer algo con I/O en la vida real, sin duda te encontrars con la duda de que API usar o que clases vas a necesitar y como ponerlas juntas.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 160
Ahora, digamos que queremos encontrar una manera menos dolorosa de escribir datos en el fichero y leer el contenido del fichero a la memoria. Empezando por la tarea de escribir datos en un fichero, hay un proceso para determinar que clase necesitaremos, y como juntarlas: 1. Ya sabemos que vamos a usar un objeto File. As que si usamos una u otra clase, una de ellas tiene que llevar un constructor que tome un objeto de tipo File.
2. Encontrar un mtodo que suene como el ms poderoso, el ms fcil de usar para hacer la tarea. Cuando miramos la tabla, podemos ver que BufferedWriter tiene el mtodo newLine(). Suena algo mejor que tener que hacer un separador a mano en cada lnea, pero ms abajo vemos que PrintWriter tiene un mtodo llamado println(). Parece que esto es lo que ms se aproxima de todo lo que tenemos. Vamos con el.
3. Cuando miramos los constructores de PrintWriter, vemos que puede construir un objeto PrintWriter si tenemos un objeto de tipo File, as que todo lo que necesitamos hacer es crear un objeto PrintWriter, tal como se muestra:
Hora de un poco de historia. Antes de Java 5, PrintWriter no tena constructores que tomaran String o File. Si estuvieras escribiendo algo de I/O en Java 1.4, como haras para conseguir que PrintWriter escribiera datos en File? Puedes imaginrtelo estudiando la tabla. Aqu hay una manera de resolver este puzle. Primero, sabemos que crearemos un objeto File al final, y que queremos un objeto PrintWriter. Podemos ver en la tabla que PrintWriter puede tambin construirse usando un objeto Writer. Aunque Writer no es una clase tal como vemos en la tabla, vemos que varias clases heredan Writer, lo que se supone como bueno, cualquier clase que herede Writer es un buen candidato. Mirando ms adelante, vemos que FileWriter tiene dos atributos que estamos buscando: 1. En el constructor se usa un File 2. Hereda Writer Dada esta informacin, podemos poner junto el siguiente cdigo (recuerda que es un ejemplo de Java 4):
Hasta aqu se ve que es fcil encadenar las clases para leer los datos del fichero a la memoria. Nuevamente, vemos que en la tabla, vemos una tabla que se llama readLine() que suena mucho mejor para leer datos. Podemos hacer el mismo proceso con el siguiente cdigo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 161
14.5 Ficheros y directorios Antes vimos que la clase File se usa para crear ficheros y directorios. Adems, los mtodo de File pueden ser usados para borrar ficheros, renombrar ficheros y determinar si un fichero existe, crear ficheros temporales, cambiar los atributos de un fichero y hacer diferencias entre fichero y directorio. Un punto en el que a menudo se confunde es que un objeto de tipo File se usa para representar un fichero o un directorio. Hablaremos de ambos en breve. Como vimos antes, el estamento:
siempre va a crear un objeto File, y luego pueden pasar una de estas cosas: 1. Si "foo" no existe, no se crea ningun fichero. 2. Si "foo" existe, el nuevo objeto File apuntara al fichero existente. Hay que fijarse que File file = new File("foo"); NUNCA crea un fichero. Hay dos maneras de crear un fichero: Invocar al mtodo createNewFile(), por ejemplo:
Crear un objeto Stream, Reader o Writer. Concretamente, un FileReader, un FileWriter, un PrintWriter, un FileInputStream o un FileOutputStream. Si creas una instancia de alguna de estas clases, estas creando un fichero, a menos que ya exista, por ejemplo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 162 Crear un directorio es similar a crear un fichero. Al igual que un fichero, crear un directorio es un proceso de dos pasos, primero creamos el directorio (usando File), luego creamos un directorio usando el mtodo mkdir().
Una vez que tienes el directorio, pones ficheros dentro, y trabajas con esos ficheros:
Este cdigo crea un fichero en el directorio. Ya que le suministras el directorio al constructor, lo que queda es el objeto File. En este caso existe una manera de escribir datos a myFile:
Ten cuidado al crear nuevos directorios! Tal como hemos visto, un Reader o un Writer crearn tu fichero automticamente si no existe, pero no es el caso de un directorio:
Esto generar una excepcin: java.io.IOException: No such file or directory Puedes referirte a un objeto File existente, ya sea fichero o directorio. Por ejemplo, asumamos que ya tenemos un subdirectorio llamado existingDir en la cual existe existingDirFile.txt, que contiene varias lneas de texto. Cuando ejecutas este cdigo:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 163 generar la siguiente salida: true true existing sub-dir data line 2 of text line 3 of text Presta especial atencin a lo que devuelve el mtodo readLine(). Cuando no hay ms lneas, el mtodo devuelve null, que es nuestra seal para parar la lectura del fichero. Tambin, no se ha invocado el mtodo flush(). Cuando se lee un fichero, no se requiere, as que no vas a encontrar un flush() en una clase de lectura (Reader). Adems de crear ficheros, la clase File te permite renombrar y borrar ficheros. El siguiente cdigo muestra una de las cosas ms comunes como el borrar y renombrar archivos:
da como salida: delDir is false y te deja un directorio llamado newDir que contiene un fichero llamado newName.txt. Aqu hay algunas reglas que podemos deducir del resultado: delete() Puedes borrar un directorio si est vaco. renameTo() Le tienes que pasar un objeto File vlido con el nuevo nombre que quieres (Si newName ha sido null, podra dar un NPE). Tambin puedes cambiar el nombre de un directorio, aunque no est vaco. Hay un montn ms para aprender en el paquete IO de Java, pero nos vamos a detener en una cosa ms, y es como buscar un fichero. Se asume que tenemos un directorio llamado searchThis que queremos buscar, el cdigo usa File.list() para crear un array de tipo String de ficheros y directorios, luego usaremos el for mejorado para recorrer el array e imprimir:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 164
Y conseguimos la siguiente salida: found dir1 found dir2 found dir3 found file1.txt found file2.txt En esta seccin hemos araado la superficie de lo que hay disponible en el paquete IO de Java. Se podra escribir un libro entero hablando de este paquete, as que obviamente hemos cubierto una muy pequea parte (pero usada frecuentemente) del API.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 165 15 Paquete I/O, la serializacin Imagina que quieres guardar el estado de uno o ms objetos. Si Java no tuviese serializacin (como vimos, en la 1.4 no lo tiene), tendras que usar una de las clases I/O para escribir el estado de las variables de instancia de todos los objetos que quieres guardar. La peor parte podra ser la reconstruccin de los objetos que fueron virtualmente creados, idnticos a los que intentas guardar. Necesitaras tu propio protocolo para crear la manera en la que habra que escribir y recuperar el estado de cada objeto, o terminaras inicializando las variables con valores equivocados. Por ejemplo, imagina que guardaste un objeto que tiene variables de instancia para la altura y el peso. A la vez que grabas el estado del objeto, podras escribir la altura y el peso como dos int en un fichero, pero el orden es crucial. Sera demasiado fcil recrear el objeto sin equivocar la posicin de los valores. La serializacin te permite decir "graba este objeto y todas sus variables de instancia". Es un poco ms interesante que eso, porque puedes aadir,... a menos que hayas marcado variables explcitamente como transient, lo que da a entender que no se incluir el valor de esa variable como parte del estado del objeto serializado.
15.1 ObjectOutputStream y ObjectInputStream La magia de la serializacin consiste en slo dos mtodos: uno para serializar objetos y escribirlos es un stream, y el otro para leer el stream y deserializar el objeto.
Estas clases son consideradas de alto nivel, y como vimos antes, significa que tendrs que envolverlas en clases de bajo nivel, al igual que las clases java.io.FileOutputStream y java.io.FileInputStream. Aqu se muestra un pequeo programa que crea un gato (Cat) que lo serializa, y deserializa.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 166 Examinemos los puntos claves de este ejemplo: Declaramos que la clase Cat implementa la interfaz Serializable. Serializable es una interfaz marcada, no tiene mtodos que implementar (En las siguientes secciones cubriremos las reglas que hablan sobre declarar clases Serializable).
Creamos un nuevo objeto Cat, que ya sabemos que es serializable.
Serializamos el objeto Cat c invocando el mtodo writeObject(). Esto tom cierto trabajo antes de que serializramos nuestro Cat. Primero, tuvimos que poner todo el cdigo entre try-catch. Luego habamos creado un objeto para escribir FileOutputStream. Despus envolvimos el FileOutputStream en un ObjectOutputStream, que es la clase que tiene el mtodo mgico de serializacin que necesitamos. Recuerda que la invocacin de writeObject() tiene dos tareas, serializa el objeto y luego lo escribe en un fichero.
Luego deserializamos el objeto invocando readObject(). El mtodo devuelve un objeto, as que tenemos que castearlo para volverlo Cat. De nuevo, tuvimos que hacer las acciones tpicas que requiere el I/O cuando trabajamos con el. Este ejemplo de serializacin ha sido a palo seco. Luego veremos casos ms complejos asociados a la serializacin. Por cuenta propia quera saber si era posible guardar ms de un objeto a la vez, intente hacer un array para guardar todos los objetos del mismo tipo pero no me sali. Sin embargo, este ejercicio me sirvi para saber tambin, que puedes guardar ms de un objeto a la vez y recuperarlos usando la operacin inversa. Es decir, guardo dos objetos Gato, y los leo de una sola vez, asignndole una variable de referencia a cada Gato guardado.
Miremos el ejercicio:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 167
La otra clase:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 168
Interesante, no es cierto? El resultado, por supuesto es correcto: Gatos guardados :) Recuperando los gatos... Tenemos a Miguel y a Juan, gatos Blanco y Marron respectivamente.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 169 15.2 Objetos grficos Que quiere decir realmente guardar un objeto? Si las variables de instancia son todas de tipo primitivo, es bastante directo. Pero qu pasa si las variables de instancia son en si mismas referencias a objetos? Que estamos grabando? Claramente, en Java no tendra sentido grabar los valores actuales de la variable de referencia porque el valor de la referencia tiene solo el contexto de la instancia de la JVM. En otras palabras, intentaras recuperar el objeto en otra instancia de la JVM, que aunque este corriendo en la misma maquina donde el objeto fue serializado, la referencia seria intil. Que le ocurre al objeto de la variable de referencia que tiene asignada? Miremos esta clase:
Ahora crearemos un perro con un collar, primero, el collar del perro con un tamao:
luego el perro, y le pasamos un collar y la talla de para el perro:
Ahora que pasa si guardas al perro? Si la finalidad es grabar y recuperar un perro, y el perro recuperado es una duplica exacta del perro que fue guardado, entonces el perro necesita un collar que sea idntico. Esto significa que el collar del perro debera haberse guardado tambin. Y qu ocurre si el collar en si mismo tambin hace referencia a otro objeto? Como el color? Esto se complica rpidamente. Si dependiera del programador saber cmo est estructurado cada objeto que se est refiriendo al perro, tendra que guardar el estado de todos los objetos... que faena. Podra ser una pesadilla con el ms simple de los objetos.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 170 Afortunadamente, el mecanismo de serializacin de Java toma esto en cuenta. Cuando serializas un objeto, la serializacin toma el objeto completo de forma grfica. Esto significa que hace una copia muy profunda de todos los objetos que son necesarios recuperar. Por ejemplo, si serializas un perro, el collar ser serializado automticamente. Y si el collar hiciera referencia a otro objeto, seria serializado tambin, y as hasta finalizar, siempre que no olvides aadir la interfaz serializable a las dems clases que incluyas en Dog. Y el nico objeto del que tienes que preocuparte es de guardar y leer al perro. Los otros objetos requeridos para reconstruir al perro son guardados y recuperados automticamente a travs de la serializacin. Recuerda que tienes que ser consciente de crear objetos serializable implementando la interfaz Serializable. Si queremos guardar al perro, tendremos que modificar la clase como sigue:
Si ahora guardamos al perro con el siguiente cdigo:
Cuando ejecutamos el cdigo, tenemos una excepcin como esta: java.io.NotSerializableException: Collar De que nos hemos olvidado? La clase collar tiene que ser Serializable tambin, si modificamos la clase collar y la hacemos serializable, no habr problema:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 171 Aqu est la lista completa:
Lo que produce:
before: collar size is 3 after: collar size is 3 Y que pasara si no tuviramos acceso al cdigo fuente del collar? En otras palabras, que pasa si hacer el collar serializable no es una opcin? Obviamente podramos crear una subclase collar serializable y luego usar la subclase en lugar del collar. Pero eso no es siempre una opcin por varias razones poderosas: 1. El collar podra ser una clase final 2. El collar podra referirse a otro objeto no serializable, y sin conocer la estructura interna, no podras hacer los arreglos necesarios. 3. Hacer subclases no es una opcin por razones de diseo. As que, qu pasa si queremos guardar al perro? Aqu es donde viene el modificador transient. Si marcas la variable de instancia con transient, la serializacin saltara el collar.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 172
Ahora tenemos un perro serializable, con un collar no serializable, pero el perro tiene el collar como transient, la salida es: before: collar size is 3 Exception in thread "main" java.lang.NullPointerException Y ahora qu hacemos??
15.3 El uso de writeObject y readObject Considera el problema, tenemos un perro que queremos grabar. El perro tiene un collar y el collar debera de ser grabado como parte del perro, pero este collar no es serializable, as que tuvimos que marcarlo como transient. Esto significa que cuando el perro se deserialice, el collar viene null. Que podemos hacer para asegurarnos de que cuando el perro se deserialice, tenga un collar que encaje con el mismo collar que tena el perro cuando fue grabado? Java tiene un mecanismo especial para este caso, un serie de mtodos privados que puedes implementar en tu clase que, si estn presentes, sern invocados automticamente durante la serializacin y la serializacin. Es casi como si los mtodos fueran definidos en la interfaz Serializable, solo que no lo estn. Forman parte de un contrato con el sistema de serializacin que bsicamente dice "Si tu (el programador) tienes un par de mtodos que encajen con esta firma exacta (lo veremos en un momento) estos mtodos sern invocados durante la serializacin y la serializacin". Estos mtodos te permiten un paso intermedio en la serializacin y la serializacin. Son perfectos para el problema del collar del perro. Cuando el perro est siendo grabado, puedes entrar a mitad del proceso y decir "de cualquier manera, me gustara aadir el estado del collar (un int) al stream cuando el perro sea serializado". Manualmente has aadido el estado del collar del perro aunque el collar como tal, no se ha grabado. Naturalmente necesitaras recuperar el collar durante la deserializacin accediendo en ese paso intermedio y diciendo "Leer un int extra que guard en el stream del perro, y lo usar para crear un collar nuevo, y luego asignare el nuevo collar al perro que est siendo deserializado". Los dos mtodos especiales que defines deben ser firmas que son exactamente como esta:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 173
Si, vamos a escribir mtodos que tienen el mismo nombre como los del ejemplo. Donde se colocan estos mtodos? Hagamos un cambio en la clase Dog (perro):
Echemos un vistazo al cdigo. En nuestro escenario hemos concretado que, por alguna razn real, no podamos serializar el collar pero, queramos serializar el perro (Dog). Para hacer esto, vamos a implementar dos mtodos, writeObject() y readObject(). Al implementar estos mtodos, le estas diciendo al compilador "Si alguien invoca writeObject() o readObject() para el objeto Dog, este cdigo tiene que ser parte de la lectura y la escritura". 1. Como la mayora de mtodos I/O, writeObject() puede arrojar excepciones. Tienes que declararlas o manejarlas, aunque recomendamos que las manejes. 2. Cuando invocas defaultWriteObject() desde el mtodo writeObject(), le estas diciendo a la JVM que haga una serializacin normal para este objeto. Cuando implementas writeObject(), normalmente estas pidiendo un proceso de serializacin normal, y adems algunos procesos personalizados de escritura y lectura. 3. En este caso hemos decidido escribir un extra int (el tamao del collar) al stream que se est creando para serializar al perro. Puedes escribir tu cdigo extra antes y/o
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 174 despus de invocar defaultWriteObject(). Pero... cuando lo lees para recuperarlo, tienes que leerlo en el mismo orden que lo grabaste. 4. De nuevo, elegimos manejar y declarar ms excepciones. 5. Cuando toca deserializar, defaultReadObject() maneja la deserializacin normal que conseguiras sino implementases readObject(). 6. Finalmente construimos un collar nuevo para el perro usando la talla que habamos serializado manualmente. (Tuvimos que invocar readInt() despus de defaultReadObject(), si no, los datos del stream saldran desincronizados!) Recuerda, la mayora de las razones para implementar writeObject() y readObject() son cuando tienes que grabar alguna parte de un objeto de forma manual. Si lo haces, cuando quieras hacer solo una parte de la serializacin/deserializacin t mismo, tienes que invocar defaultReadObject() y defaultWriteObject(). Lo que trae otra pregunta, por qu no se pueden serializar todas las clases de Java? Por qu no es Object serializable? Hay muchas cosas en Java que no pueden ser serializadas porque estn en un entorno de ejecucin especfico. Cosas como streams, threads, runtime, etc. y algunas clases GUI (las cuales estn conectadas al sistema operativo) no pueden serializarse. Lo que es y no es serializable en Java no tienes que dominarlo, pero necesitars tenerlo en cuenta si quieres serializar objetos complejos.
15.4 La herencia y la serializacin La serializacin es algo sensacional, pero para aplicarla efectivamente tienes que entender como la superclase afecta a la serializacin.
Esto nos trae otro tema clave con la serializacin... qu pasa si una superclase no est marcada como Serializable pero su subclase lo est? Puede la subclase ser serializada aunque su superclase no lo sea? Imagnate lo siguiente:
Ahora t tienes la clase perro serializable, con una superclase no serializable. Esto funciona! Pero hay importantes implicaciones. Para entender estas implicaciones, miremos la diferencias entre un objeto que viene de una serializacin, y otro que se ha creado con new. Recuerda, cuando un objeto se construye con new (lo opuesto a uno de una serializacin), ocurren estos hechos en este orden: 1. Todas las variables de instancia son iniciadas con el valor por defecto. 2. El constructor es invocado, lo cual implica que se invoca el constructor de la superclase (u otro constructor sobrecargado, hasta que se invoque el constructor de la superclase.) 3. Todos los constructores de la superclase se completan.
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 175 4. Las variables de instancia inicializadas como parte de su declaracin se les asigna su valor inicial (lo contrario a los valores por defecto, son valores dados a priori por los constructores de la superclase.) 5. El constructor finaliza. Pero nada de esto ocurre en un objeto deserializado. Cuando una instancia de una clase serializada se deserializa, el constructor no se ejecuta, y las variables de instancia no se les asigna ningn valor inicial! Piensa en ello, si el constructor fuese invocado, o las variables de instancia se le asignasen los valores iniciales, el objeto que intentas recuperar en el estado que lo grabaste, volvera totalmente alterado. Por ejemplo, imagina que tienes una clase que declara una variable de instancia y le asigna el valor int 3, y le incluyes un mtodo que le cambia el valor a 10:
Obviamente, si serializas Foo despus de que el mtodo changeNum() se ejecute, el valor de la variable nim seria 10. Cuando la instancia Foo se deserializa, t quieres que la variable mantenga su valor de 10! Obviamente no quieres que se inicialice (en este caso, con el 3). Piensa en el constructor y la asignacin a la variable de instancia como una parte completada de la inicializacin del objeto (y el hecho, es que ellos hacen la inicializacin en el bytecode). El punto es, que cuando un objeto se deserializa no queremos que se ejecute la inicializacin. No queremos que el constructor se ejecute, y no queremos explcitamente valores declarados. Slo queremos los valores con los que fue grabado. Naturalmente si tienes variables marcadas como transient, no sern recuperadas con su valor original (a menos que implementes defaultReadObject()), pero en su lugar, se le darn los valores por defecto para el tipo de dato. En otras palabras, aunque digas:
cuando la instancia de Bar se deserialice, la variable x tendr el valor cero. Los objetos de referencia marcados como transient siempre se resetearan a null, no importa si fueron inicializados en tiempo de declaracin de la clase. As, que esto es lo que ocurre cuando el objeto se deserializa, y la clase serializada directamente hereda Object, o tiene solo clases serializables en su rbol de herencia. Tiene algo de trampa cuando la clase serializable tiene una o ms clases no serializables en su superclase. Volviendo a nuestra clase Animal con un Dog serializable:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 176
Ya que Animal no es serializable, cualquier estado mantenido en Animal, incluso la variable que se hereda en Dog, no va a ser recuperada cuando se deserialice! La razn es, que la clase Animal (no serializable) que es parte de Dog va a ser reiniciada igual que si estuvieras haciendo un nuevo Dog. En otras palabras, las variables de instancia de Dog sern serializadas y deserializadas correctamente, pero las variables heredadas de Animal sern iniciadas con sus valores por defecto. Si tienes una clase serializable pero tu superclase no lo es, entonces cualquier variable de instancia que heredes de la superclase reseteara sus valores a los suyos por defecto. Esto es porque el constructor de la superclase se ejecutar! De hecho, cada constructor encima de la clase no serializable tambin se ejecutar, no importa, porque una vez que el primer superconstructor sea invocado, su curso invocar sus superconstructores hasta el principio del rbol de herencia. Necesitars tambin reconocer que variables sern recuperadas y cules no, as que asegrate de estudiar el siguiente ejemplo y la salida:
Curso gratuito de Java en emuladores L2 Java 2012 e m a i l : b r u j u l a t o @y a h o o . e s
Pgina 177 Da como resultado: before: Fido 35 after: Fido 42 La clave aqu es Animal, que no es serializable, cuando el Dog fue deserializado, el constructor de Animal se ejecut y reseteo la variable weight.
15.5 Serializacin y clases estticas Finalmente, te has podido dar cuenta que hemos hablado solo de variables de instancia, no de variables estticas. Las variables estticas deberan ser grabadas aparte del estado del objeto? No es importante que la variable esttica sea serializada con el objeto? Si y no. Puede ser importante pero no es una parte del estado de la instancia. Recuerda, que debes pensar que las variables estticas son puramente variables de clase. Ellas no tienen nada que ver con las instancias individuales. Pero la serializacin se aplica solo a los objetos. Y que sucede si deserializa tres instancias distintas de Dog, que fueron serializados a distinta vez, y que todos fueron grabados con una variable esttica en la clase con un valor distinto? Que instancia debera prevalecer? Qu valor esttico debera ser usado para reemplazar el actual en cada clase Dog que est cargado actualmente? Ves el problema? Las variables estticas nunca se graban como parte del estado del objeto, porque no pertenecen al objeto!