Documentos de Académico
Documentos de Profesional
Documentos de Cultura
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.
Kimeraweb
email: brujulato@yahoo.es
msn: kimera@kimeraweb.es
fb: kimera kimeraweb
16/09/2012
2012
Pgina 1
2012
email: brujulato@yahoo.es
Pgina 2
2012
email: brujulato@yahoo.es
Pgina 3
2012
email: brujulato@yahoo.es
Pgina 4
2012
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...
email: brujulato@yahoo.es
Pgina 5
2012
email: brujulato@yahoo.es
Pgina 6
2012
Al principio cit objeto comn porque ms adelante veremos otra clase de objetos.
email: brujulato@yahoo.es
Pgina 7
2012
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.
email: brujulato@yahoo.es
Pgina 8
2012
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.
email: brujulato@yahoo.es
Pgina 9
2012
email: brujulato@yahoo.es
Pgina 10
2012
email: brujulato@yahoo.es
Pgina 11
2012
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.
email: brujulato@yahoo.es
Pgina 12
2012
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:
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.
email: brujulato@yahoo.es
Pgina 13
2012
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:
email: brujulato@yahoo.es
Pgina 14
2012
email: brujulato@yahoo.es
Pgina 15
2012
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.
email: brujulato@yahoo.es
Pgina 16
2012
email: brujulato@yahoo.es
Pgina 17
2012
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.
email: brujulato@yahoo.es
Pgina 18
2012
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.
email: brujulato@yahoo.es
Pgina 19
2012
esttica
es
accesible
directamente,
Mtodos
Variables
Clases anidadas (no dentro de un mtodo, se ver ms adelante)
Inicializacin de bloques
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.
email: brujulato@yahoo.es
Pgina 20
2012
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 {
public void digoHola(String nombre)
{
System.out.print ("HOLA " + nombre);
}
}
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.
email: brujulato@yahoo.es
Pgina 21
2012
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.
email: brujulato@yahoo.es
Pgina 22
2012
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.
email: brujulato@yahoo.es
Pgina 23
2012
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.
email: brujulato@yahoo.es
Pgina 24
2012
email: brujulato@yahoo.es
Pgina 25
2012
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 (){}
email: brujulato@yahoo.es
Pgina 26
2012
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.
email: brujulato@yahoo.es
Pgina 27
2012
email: brujulato@yahoo.es
Pgina 28
2012
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.
email: brujulato@yahoo.es
Pgina 29
2012
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.
valor
entre
4.94065645841246544e-324d
email: brujulato@yahoo.es
Pgina 30
2012
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:
email: brujulato@yahoo.es
Pgina 31
2012
Que es inicializar una variable? Asignarle un valor (aunque sea un valor vaco).
email: brujulato@yahoo.es
Pgina 32
2012
email: brujulato@yahoo.es
Pgina 33
2012
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:
email: brujulato@yahoo.es
Pgina 34
2012
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:
email: brujulato@yahoo.es
Pgina 35
2012
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).
email: brujulato@yahoo.es
Pgina 36
2012
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:
email: brujulato@yahoo.es
Pgina 37
2012
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.
email: brujulato@yahoo.es
Pgina 38
2012
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:
email: brujulato@yahoo.es
Pgina 39
2012
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 ESUN. Por ejemplo, si Box implementa Foldable, lo siguiente, es vlido:
email: brujulato@yahoo.es
Pgina 40
2012
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:
Este cdigo:
email: brujulato@yahoo.es
Pgina 41
2012
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:
email: brujulato@yahoo.es
Pgina 42
2012
email: brujulato@yahoo.es
Pgina 43
2012
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:
email: brujulato@yahoo.es
Pgina 44
2012
email: brujulato@yahoo.es
Pgina 45
2012
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.
email: brujulato@yahoo.es
Pgina 46
2012
Imaginemos que necesitamos devolver el tipo de combustible del coche, por defecto son todos
gasolina pero el comercial sera diesel.
email: brujulato@yahoo.es
Pgina 47
2012
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!
email: brujulato@yahoo.es
Pgina 48
2012
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:
email: brujulato@yahoo.es
Pgina 49
2012
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.
email: brujulato@yahoo.es
Pgina 50
2012
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?
email: brujulato@yahoo.es
Pgina 51
2012
y Coder ni se entera.
email: brujulato@yahoo.es
Pgina 52
2012
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.
email: brujulato@yahoo.es
Pgina 53
2012
email: brujulato@yahoo.es
Pgina 54
2012
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.
email: brujulato@yahoo.es
Pgina 55
2012
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.
email: brujulato@yahoo.es
Pgina 56
2012
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):
email: brujulato@yahoo.es
Pgina 57
2012
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.
email: brujulato@yahoo.es
Pgina 58
2012
Aunque es raro usar esto de esta manera, nunca est de ms saber que existe y como
funciona.
email: brujulato@yahoo.es
Pgina 59
2012
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.
email: brujulato@yahoo.es
Pgina 60
2012
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.
email: brujulato@yahoo.es
Pgina 61
2012
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.
email: brujulato@yahoo.es
Pgina 62
2012
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.
email: brujulato@yahoo.es
Pgina 63
2012
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.
email: brujulato@yahoo.es
Pgina 64
2012
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.
email: brujulato@yahoo.es
Pgina 65
2012
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:
email: brujulato@yahoo.es
Pgina 66
2012
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.
email: brujulato@yahoo.es
Pgina 67
2012
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:
email: brujulato@yahoo.es
Pgina 68
2012
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.
email: brujulato@yahoo.es
Pgina 69
2012
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:
email: brujulato@yahoo.es
Pgina 70
2012
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:
email: brujulato@yahoo.es
Pgina 71
2012
email: brujulato@yahoo.es
Pgina 72
2012
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.
email: brujulato@yahoo.es
Pgina 73
2012
email: brujulato@yahoo.es
Pgina 74
2012
email: brujulato@yahoo.es
Pgina 75
2012
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:
email: brujulato@yahoo.es
Pgina 76
2012
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.
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.
email: brujulato@yahoo.es
Pgina 77
2012
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.
email: brujulato@yahoo.es
Pgina 78
2012
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.
email: brujulato@yahoo.es
Pgina 79
2012
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
email: brujulato@yahoo.es
Pgina 80
2012
sean eliminados de la memoria. La nica cosa que se garantiza es que el GC funcionara antes
de arrojar una excepcin OutOfMemoryException.
email: brujulato@yahoo.es
Pgina 81
2012
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.
email: brujulato@yahoo.es
Pgina 82
2012
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:
email: brujulato@yahoo.es
Pgina 83
2012
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.
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.
email: brujulato@yahoo.es
Pgina 84
2012
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.
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
email: brujulato@yahoo.es
Pgina 85
2012
Sabemos que }} es bastante feo de ver, pero te estoy preparando. Esto da como salida:
==
dot equals
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.
email: brujulato@yahoo.es
Pgina 86
2012
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:
email: brujulato@yahoo.es
Pgina 87
2012
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:
+ sumar
- restar
* multiplicacin
/ divisin
email: brujulato@yahoo.es
Pgina 88
2012
Recuerda: Las expresiones son evaluadas de izquierda a derecha por defecto, Puedes cambiar
esta secuencia aadiendo parntesis. Tambin recuerda que *,/ y % preceden sobre + y -.
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:
email: brujulato@yahoo.es
Pgina 89
2012
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:
email: brujulato@yahoo.es
Pgina 90
2012
%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.
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:
email: brujulato@yahoo.es
Pgina 91
2012
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
&& AND
|| OR
email: brujulato@yahoo.es
Pgina 92
2012
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
da como resultado
% java TestOR
i < 5
Result is true
i >= 5
i >= 5
email: brujulato@yahoo.es
Pgina 93
2012
Pgina 94
2012
not equal
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.
email: brujulato@yahoo.es
Pgina 95
2012
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:
email: brujulato@yahoo.es
Pgina 96
2012
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:
email: brujulato@yahoo.es
Pgina 97
2012
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.
email: brujulato@yahoo.es
Pgina 98
2012
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.
email: brujulato@yahoo.es
Pgina 99
2012
Qu pasa si usas una variable menor que un int en un switch? Observa el ejemplo:
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:
email: brujulato@yahoo.es
Pgina 100
2012
Es lcito aprovechar la potencia del boxing en una expresin switch. Por ejemplo, esto es
vlido:
En este ejemplo, el case green: encaja, as que la JVM ejecutar ese bloque y los subsiguientes
produciendo la salida:
green blue done
email: brujulato@yahoo.es
Pgina 101
2012
mostrar:
x is one
x is two
x is three
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:
email: brujulato@yahoo.es
Pgina 102
2012
email: brujulato@yahoo.es
Pgina 103
2012
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.
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:
email: brujulato@yahoo.es
Pgina 104
2012
El cdigo devuelve:
past the loop
Ya que la expresin (x > 8) se evala falsa, nada en el interior del cuerpo se ejecuta.
email: brujulato@yahoo.es
Pgina 105
2012
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.
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:
email: brujulato@yahoo.es
Pgina 106
2012
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 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.
email: brujulato@yahoo.es
Pgina 107
2012
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:
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:
email: brujulato@yahoo.es
Pgina 108
2012
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
Resultado:
12341234
email: brujulato@yahoo.es
Pgina 109
2012
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.
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.
email: brujulato@yahoo.es
Pgina 110
2012
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:
email: brujulato@yahoo.es
Pgina 111
2012
Como nota personal, tengo que aadir que no vi claro el uso de continue, as que desarroll el
siguiente cdigo:
loop 0
loop 1
loop 2
loop 3
loop 4
loop 5
loop 6
loop 7
loop 8
loop 9
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.
email: brujulato@yahoo.es
Pgina 112
2012
En este ejemplo, el estamento break esta sin etiquetar. El siguiente ejemplo es un ejemplo
de continue etiquetado:
email: brujulato@yahoo.es
Pgina 113
2012
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:
email: brujulato@yahoo.es
Pgina 114
2012
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:
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.
email: brujulato@yahoo.es
Pgina 115
2012
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.
email: brujulato@yahoo.es
Pgina 116
2012
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:
email: brujulato@yahoo.es
Pgina 117
2012
email: brujulato@yahoo.es
Pgina 118
2012
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:
email: brujulato@yahoo.es
Pgina 119
2012
email: brujulato@yahoo.es
Pgina 120
2012
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.
email: brujulato@yahoo.es
Pgina 121
2012
email: brujulato@yahoo.es
Pgina 122
2012
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.
email: brujulato@yahoo.es
Pgina 123
2012
email: brujulato@yahoo.es
Pgina 124
2012
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:
email: brujulato@yahoo.es
Pgina 125
2012
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:
email: brujulato@yahoo.es
Pgina 126
2012
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:
email: brujulato@yahoo.es
Pgina 127
2012
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:
email: brujulato@yahoo.es
Pgina 128
2012
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:
email: brujulato@yahoo.es
Pgina 129
2012
En este programa se le pasa mediante parmetros la comida, y si no es del agrado, lanzar una
excepcin.
email: brujulato@yahoo.es
Pgina 130
2012
A continuacin expongo como lanzar una aplicacin con Eclipse adjuntando parmetros:
email: brujulato@yahoo.es
Pgina 131
2012
email: brujulato@yahoo.es
Pgina 132
2012
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.
email: brujulato@yahoo.es
Pgina 133
2012
ClassCastException
IllegalArgumentException
IllegalStateException
NullPointerException
NumberFormatException
AssertionError
ExceptionInInitializerError
StackOverflowError
NoClassDefFoundError
Descripcin
Arrojado cuando se intenta acceder a
un array con un valor ndex equivocado
(negativo o mayor que la longitud del
array)
Arrojado cuando se intenta castear una
variable de referencia de un tipo que no
pasa el test ES-UN
Arrojado cuando un mtodo recibe un
argumento formateado de diferente
manera que lo que espera el mtodo.
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.
Arrojado cuando se intenta acceder a
un objeto con una variable de
referencia null.
Arrojado cuando un mtodo que
convierte una cadena a un nmero,
recibe una cadena que no puede ser
convertida.
Arrojado cuando el test booleano
devuelve falso.
Arrojado cuando se intenta inicializar
una variable esttica o un bloque.
Se arroja cuando un mtodo se recurre
profundamente. Cada invocacin se
aade a la pila.
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.
Arrojado por
JVM
JVM
Programado
Programado
JVM
Programado
JVM
JVM
JVM
JVM
email: brujulato@yahoo.es
Pgina 134
2012
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.
email: brujulato@yahoo.es
Pgina 135
2012
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:
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.
email: brujulato@yahoo.es
Pgina 136
2012
email: brujulato@yahoo.es
Pgina 137
2012
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:
email: brujulato@yahoo.es
Pgina 138
2012
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:
email: brujulato@yahoo.es
Pgina 139
2012
Tambin tienes que conocer la lnea de comandos para desactivar las aserciones:
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.
email: brujulato@yahoo.es
Pgina 140
2012
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:
y tres clases:
com.geeksanonymous.Foo
com.geeksanonymous.twelvesteps.StepOne
com.geeksanonymous.twelvesteps.StepTwo
email: brujulato@yahoo.es
Pgina 141
2012
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.
email: brujulato@yahoo.es
Pgina 142
2012
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.
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.
email: brujulato@yahoo.es
Pgina 143
2012
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:
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:
email: brujulato@yahoo.es
Pgina 144
2012
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:
email: brujulato@yahoo.es
Pgina 145
2012
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.
email: brujulato@yahoo.es
Pgina 146
2012
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.
email: brujulato@yahoo.es
Pgina 147
2012
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.
email: brujulato@yahoo.es
Pgina 148
2012
email: brujulato@yahoo.es
Pgina 149
2012
email: brujulato@yahoo.es
Pgina 150
2012
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:
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.
email: brujulato@yahoo.es
Pgina 151
2012
email: brujulato@yahoo.es
Pgina 152
2012
Esto es todo para StringBuffer y StringBuilder. Recuerda que al contrario de los objetos String,
StringBuffer y StringBuilder si mutan.
email: brujulato@yahoo.es
Pgina 153
2012
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.
email: brujulato@yahoo.es
Pgina 154
2012
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:
Y tambin produce un fichero vaco en tu directorio. Si ejecutas el cdigo una segunda vez, se
mostrar:
true
false
true
email: brujulato@yahoo.es
Pgina 155
2012
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:
email: brujulato@yahoo.es
Pgina 156
2012
Lo que ha pasado:
El metodo read() ley todo el fichero, un carcter cada vez, y ponerlo dentro de char[].
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.
email: brujulato@yahoo.es
Pgina 157
2012
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:
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?
email: brujulato@yahoo.es
Pgina 158
2012
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.
email: brujulato@yahoo.es
Pgina 159
2012
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:
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:
email: brujulato@yahoo.es
Pgina 160
2012
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:
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:
email: brujulato@yahoo.es
Pgina 161
2012
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:
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:
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:
email: brujulato@yahoo.es
Pgina 162
2012
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:
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:
email: brujulato@yahoo.es
Pgina 163
2012
dir1
dir2
dir3
file1.txt
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.
email: brujulato@yahoo.es
Pgina 164
2012
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.
email: brujulato@yahoo.es
Pgina 165
2012
Creamos
un
nuevo
objeto
Cat,
que
ya
sabemos
que
es
serializable.
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:
email: brujulato@yahoo.es
Pgina 166
2012
La otra clase:
email: brujulato@yahoo.es
Pgina 167
2012
email: brujulato@yahoo.es
Pgina 168
2012
Ahora crearemos un perro con un collar, primero, el collar del perro con un tamao:
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.
email: brujulato@yahoo.es
Pgina 169
2012
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:
email: brujulato@yahoo.es
Pgina 170
2012
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.
email: brujulato@yahoo.es
Pgina 171
2012
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??
email: brujulato@yahoo.es
Pgina 172
2012
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):
email: brujulato@yahoo.es
Pgina 173
2012
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.
email: brujulato@yahoo.es
Pgina 174
2012
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:
email: brujulato@yahoo.es
Pgina 175
2012
email: brujulato@yahoo.es
Pgina 176
2012
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.
email: brujulato@yahoo.es
Pgina 177