oracle certified professional java se 6 programmer 2

50
México Distrito Federal a 28 de Febrero de 2014 Autor: Pablo Galeana Bailey Cualquier duda y/o comentario quedo a sus órdenes para alguna asesoría o recomendación para mejorar el presente material. Email: [email protected] 1. Objetivo de Certificación 5.1 - Encapsulación Desarrollar código que implemente una fuerte encapsulación, un bajo acoplamiento y una alta cohesión en clases, describiendo posteriormente los beneficios. El desarrollador debe escribir las clases y el código de forma que soporte flexibilidad y mantenibilidad. Como ejemplo, una clase con las variables de instancia públicas, y el resto de programadores están modificando las variables directamente, tal y como se muestra a continuación:

Upload: pablo-galeana-bailey

Post on 13-Jun-2015

294 views

Category:

Education


2 download

DESCRIPTION

SCJP , Curso SCJP

TRANSCRIPT

Page 1: Oracle certified professional  java se 6 programmer 2

México Distrito Federal a 28 de Febrero de 2014

Autor: Pablo Galeana Bailey

Cualquier duda y/o comentario quedo a sus órdenes para alguna asesoría orecomendación para mejorar el presente material.

Email: [email protected]

1. Objetivo de Certificación 5.1 - EncapsulaciónDesarrollar código que implemente una fuerte encapsulación, un bajoacoplamiento y una alta cohesión en clases, describiendo posteriormente losbeneficios.

El desarrollador debe escribir las clases y el código de forma que soporteflexibilidad y mantenibilidad. Como ejemplo, una clase con las variables deinstancia públicas, y el resto de programadores están modificando las variablesdirectamente, tal y como se muestra a continuación:

Page 2: Oracle certified professional  java se 6 programmer 2

Lo ideal sería crear un método setSize(int a) para controlar los valores y modificarla visibilidad de la variable para hacerla privada. Sin embargo, esto hará que todoel código que hace uso de esta clase genere errores.La capacidad de hacer cambios en nuestro código de implementación sin romperel resto que use el código es un beneficio clave de la encapsulación. Lo ideal esocultar los detalles de implementación tras una interfaz de programación pública.Por interfaz se entiende el conjunto de métodos accesibles que nuestro códigopone a disponibilidad pública - o lo que es lo mismo, la API de nuestro código.Ocultando los detalles de implementación, podemos modificar el código sinnecesidad de modificar el código que llama a nuestros métodos.

Si queremos mantenibilidad, flexibilidad y extensabilidad nuestro diseño debeincluir encapsulación:

Mantener las variables de instancia protegidas (con un modificador de acceso,normalmente privado).

Hacer métodos de acceso público y forzar al código para que use dichosmétodos en lugar de que accedan directamente a la variable de instancia.

Restringir el acceso a obtener el valor que lleva el atributo Si no ponemos elmétodo Get, solo se podrá acceder desde la propia clase a este atributo.

Restringir el acceso a modificar el valor que lleva el atributo Si no ponemos elmétodo set, solo se podrá acceder desde la propia clase a este atributo.

Para los métodos, utilizar la convención de nombrado JavaBeans(set<Propiedad> y get<Propiedad>).

A estos métodos se les conoce como getters y setters (algunas veces comoaccesors y mutators). Implementación del ejemplo anterior pero con métodossetters y getters:

Page 3: Oracle certified professional  java se 6 programmer 2

El código anterior no realiza ninguna validación o procesamiento por lo que podríapensarse que no es útil. Sin embargo, podríamos cambiar en un futuro dichaimplementación sin necesidad de cambiar la signatura del método y, por tanto, sinromper nuestra API. Con esto obtenemos las ventajas de un buen diseño OO.Debemos siempre forzar al código llamante a que acceda a las variables a travésde métodos públicos.

2. Objetivo de Certificación 5.5 - Herencia, "Es-Un" (Is-A) y "Tiene-Un" (Has-A)Desarrollar código que implemente relaciones "Is-A" o/y "Has-A"

La instrucción instanceof devuelve 'true' si la variable que estamos probando esdel mismo tipo del que comparamos.El siguiente código:

Produce la siguiente salida:they'renotequalt1's anObject

Vemos dos aspectos claves: t1 no es igual a t2, aunque no está el método equals() (¿o sí está?). t1 es una instancia de la clase Object (¿no era de la clase Test?).

Esto se debe a que toda clase en Java es una subclase de Object. Siempre quecreamos una clase, dicha clase heredará de Object y por tanto heredará susmétodos (equals, clone, notify, wait y otros disponibles).

Page 4: Oracle certified professional  java se 6 programmer 2

Para el examen, necesitaremos saber que podemos crear relaciones deherencia en Java extendiendo una clase.

Es también importante comprender que las dos razones más comunes para usarherencia son:

1.- Promocionar la reutilización de código:Un diseño común de aproximación escrear una versión genérica de una clase con la intención de crear subclases másespecializadas que hereden de ella. Por ejemplo:

Genera la siguiente salida:displayingshapemovinggamepiece

Aquí, PlayinPiece hereda el método genérico display() de una clase menosespecializada (GameShape) y además añade su propio método, movePiece(). Lareutilización de código a través de la herencia se utiliza para métodos confuncionalidad genérica que podrían aplicarse a un amplio rango de subclases, porlo que no sería necesario reimplementarlos en cada objeto.

2.-Usar polimorfismo: el uso de herencia es para permitir a nuestras clases seraccedidas de forma polimórfica (capacidad también proporcionada por lasinterfaces). Por ejemplo, imaginemos que tenemos una clase GameLauncher quequiere recorrer una lista de distintos objetos GameShape e invocar el método

Page 5: Oracle certified professional  java se 6 programmer 2

display() en cada uno de ellos. En el momento de escribir la clase no sabemos quétipos de figuras tendremos y además no querremos tener que cambiar el código sise añade una nueva figura.El polimorfismo permite tratar cualquier subclase de GameShape como un objetoGameShape. Imaginemos que ahora tenemos dos subclases que extienden de laclase GameShape:

Ahora imagina una clase de prueba que tiene un método con un argumento de tipoGameShape, lo que significa que puede tomar cualquier tipo de GameShape.El siguiente código:

Generaría la siguiente salida:

Page 6: Oracle certified professional  java se 6 programmer 2

displayingshapedisplayingshape

El punto clave es que el método doShapes() está declarado con un argumentoGameShape por lo que se le puede pasar cualquier subtipo de GameShape. Elmétodo puede invocar cualquier método de GameShape, sin preocuparse del tipode clase en ejecución que ha sido pasado al objeto. Sin embargo, usar unavariable de referencia declarada de tipo GameShape (ya sea un parámetro demétodo, una variable local o una variable de instancia) significa que sólopodremos invocar los métodos de GameShape. Los métodos que podemos llamaren una referencia son totalmente dependientes del tipo de variable declarada, noimporta qué tipo de objeto actual esté apuntando la referencia.

2.1. Relaciones Is-A y Has-A

IS-AEn OO, el concepto de IS-A está basado en la herencia de clase o implementaciónde interfaz. IS-A es una forma de decir, "A es un tipo de B". Por ejemplo, unSubaru es un tipo de Coche, por lo que en términos de OO podríamos decir,"Subaru IS-A Car". Podemos expresar esta relación en Java mediante las palabrasreservadas 'extends' (para herencia de clase) e 'implements' (paraimplementación de interfaz).

Un Coche es un tipo de Vehículo, por lo que el árbol de herencia podría empezarpor la clase Vehicle, tal y como se muestra a continuación:

Page 7: Oracle certified professional  java se 6 programmer 2

En términos de OO podríamos decir:

Vehicle es la superclase de Car. Car es la subclase deVehicle. Car es la superclase de Subaru. Subaru es la subclase de Vehicle. Car hereda de Vehicle. Subaru hereda de Vehicle y Car. Subaru deriva de Car. Car deriva de Vehicle. Subaru deriva de Vehicle. Subaru es un subtipo de Vehicle y Car.

Volviendo a nuestra relación IS-A, las siguientes sentencias son ciertas: "Car extends Vehicle" significa"Car IS-A Vehicle." "Subaru extends Car" significa "Subaru IS-A Car."

También podemos decir:"Subaru IS-A Vehicle" puesto que se dice que es "un tipo de cualquier clasesuperior de su árbol de herencia". Si la expresión Fooinstanceof Bar es cierta,entonces Foo IS-A Bar, aún cuando Foo no extienda directamente a Bar sino queextiende una clase que es subclase de Bar.Ejemplo: Modelar por medio de la herencia el siguiente diagrama de clases:

Page 8: Oracle certified professional  java se 6 programmer 2

HAS-ALas relaciones HAS-A están basadas en el uso. En otras palabras, la clase AHAS-A B si en código en la clase A tiene una referencias a una instancia de laclase B. Por ejemplo:"Un Horse IS-A Animal. Un Horse HAS-A Halter (rienda)".El código podría ser el siguiente:

En el código anterior, la clase Horse tiene una variable de instancia de tipo Halter,por lo que podremos decir "Horse HAS-A Halter".

Los usuarios de la clase Horse (los que hacen llamadas a dicha clase) piensanque la clase Horse tiene el comportamiento definido por Halter. La clase Horsepodría tener un método tie(LeadRoperope) (atar las riendas). Los usuarios notiene que saber que cuando invoquen el método tie(), el objeto Horse delegue lallamada a su clase Halter. Veamos esto en código:

Page 9: Oracle certified professional  java se 6 programmer 2

En OO, nosotros no queremos que los usuarios se preocupen sobre qué clase oqué objeto está haciendo el trabajo.

3. Objetivo de Certificación 5.2 – Polimorfismo

Dado un escenario, desarrollar código que demuestre el uso de polimorfismo. Esmás, determinar cualdo será necesario un casting y reconocer errores decompilación vs ejecución relacionados con el casting de referencias de objetos

Cualquier objeto Java que pueda pasar más de una prueba IS-A puede serconsiderado polimórfico.Todos los objetos Java son polimórficos puesto que pasan la prueba IS-A para supropio tipo y para la clase Object. Recordar unas cuantas cosas sobre lasreferencias:

Una variable de referencia sólo puede ser de un tipo y, una vez declarada, nopuede cambiarse el tipo (aunque cambie el objeto al que referencie).

Una referencia es una variable, por lo que puede ser reasignada a otrosobjetos (a no ser que la referencia se declare como 'final').

Un tipo de la variable de referencia determina los métodos que podráninvocarse en el objeto que está referenciando la variable.

Una variable de referencia puede apuntar a cualquier objeto del mismo tipo quela referencia declarada o -esto es lo más importante- puede apuntar a cualquiersubtipo del tipo declarado.

Una variable de referencia puede ser declarada como un tipo de clase o un tipode interfaz. Si la variable es declarada como un tipo de interfaz, puedereferenciar a cualquier objeto de cualquier clase que implemente la interfaz.

Antes creamos una clase GameShape que fue extendida por otras dos clases,PlayerPiece y TilePiece. Ahora imaginemos que queremos animar alguna de lasfiguras en el tablero de juego. Pero no todas las formas pueden ser animadas, porlo que ¿cómo podríamos hacer esto con herencia de clase?.

La solución correcta sería crear una interfaz Animatable y hacer que sólo lassubclases de Gameshape que puedan ser animadas implementen dicha interfaz.A continuación se muestra dicha interfaz:

Y a continuación se muestra la clase modificada PlayerPiece que implementadicha interfaz:

Page 10: Oracle certified professional  java se 6 programmer 2

Ahora tenemos un PlayerPiece que pasa la prueba IS-A para la clase Gameshapey para la interfaz Animatable.Esto significa que PlayerPiece puede ser tratado de forma polimórfica como unode los cuatro tipos en cualquier momento, en función del tipo declarado en lavariable de referencia:

Un objeto (puesto que cualquier objeto hereda de Object) Un GameShape (puesto que PlayerPiece extiende a GameShape) Un PlayerPiece (es realmente lo que es) Un Animatable (puesto que PlayerPiece implementa Animatable)

Las siguientes declaraciones son todas legales.

Sólo tenemos un objeto una instancia del tipo PlayerPiece- pero hay cuatro tiposdistintos de variables de referencia, todas apuntando a un objeto.Puesto que estadefinición depende de una comprensión clara de la sobrescritura (override) y ladistinción entre métodos estáticos y métodos de instancia.

Ejemplo: Modelar por medio del polimorfismo el siguiente diagrama de clases:

Page 11: Oracle certified professional  java se 6 programmer 2
Page 12: Oracle certified professional  java se 6 programmer 2
Page 13: Oracle certified professional  java se 6 programmer 2

El siguiente diagrama de clases representa la jerarquía de herencia de lasclases asociadas a los tipos primitivos en Java

4. Objetivos de Certificación 1.5 y 5.4 - Sobrescritura/Sobrecarga1.5 - Dado un código de ejemplo, determinar si un método está sobrescribiendo osobrecargando correctamente otro método e identificar los valores de retornolegales (incluyendo retornos covariantes) para el método.

4.1. Métodos SobrescritosCuando tenemos una clase que hereda un método de una superclase, tenemos laoportunidad de sobrescribir el método (a no ser que esté marcado como 'final'). El

Page 14: Oracle certified professional  java se 6 programmer 2

principal beneficio de la sobrescritura es la capacidad de definircomportamiento que es específico a un tipo de subclase particular.Ejemplo laclase Horse, sublcase de Animal, sobrescribiendo su método eat():

Si heredamos métodos abstractos no tenemos otra opción,debemos implementarel método en la subclase a no ser que la subclase también sea abstracta. Losmétodos abstractos deben ser implementados por la subclase concreta, aunqueesto es como decir que la subclase concreta sobrescriba los métodos abstractosde la superclase. Por lo que podemos decir que los métodos abstractos sonmétodos que estamos forzados a sobrescribir."No existe forma alguna de usar un método eat() genérico, sino que tenemos quecrear nuestra propia implementación del método".Un (no abstracto) ejemplo del uso de polimorfismo podría ser el siguiente:

En el código anterior, la clase de prueba usa una referencia Animal para invocarun método del objeto Horse. Recuerda que el compilador sólo permitirá que seinvoquen métodos de la clase Animal cuando usamos una referencia de este tipo.

El siguiente código no sería legal si tenemos en cuenta el código anterior:

Page 15: Oracle certified professional  java se 6 programmer 2

El método que sobrescribe no puede tener un modificador de acceso másrestrictivo que el método que está sobrescribiendo. Modifiquemos el ejemplopolimórfico que vimos anteriormente:

Si el código compilara (lo cual no es correcto) lo siguiente produciría un fallo entiempo de ejecución:

La variable 'b' es de tipo Animal, el cual tiene un método público eat(). Perorecuerda que en tiempo de ejecución, Java utiliza la invocación virtual de métodospara seleccionar de forma dinámica la versión actual del método que va a ejecutar,basándose en la instancia actual. Una referencia Animal siempre puede apuntar auna instancia Horse, puesto que HorseIS-A Animal. Lo que significa que lasuperclase apunte a una instancia de una subclase es que se garantiza que lasubclase es capaz de hacer todo lo que puede hacer la superclase. Si la instanciaHorse sobrescribe los métodos heredades de Animal o simplemente los hereda,cualquiera con una referencia a una instancia Horse es libre de llamar a todos losmétodos accesibles de Animal. Por dicha razón, un método que sobrescribe debecumplir el contrato de la superclase.

Las reglas para sobrescribir un método son las siguientes:

La lista de argumentos debe ser exactamente la misma que la del métodosobrescrito. Si no encajan, tendremos un método sobrecargado.

Page 16: Oracle certified professional  java se 6 programmer 2

El tipo devuelto debe ser el mismo, o un subtipo, del tipo de retorno declaradoen el método original de la superclase.

El nivel de acceso no puede ser más restrictivo que el del método sobrescrito. El nivel de acceso puede ser menos restrictivo que el del método sobrescrito. Los métodos de la instancia pueden ser sobrescritos sólo si son heredados de

la subclase. Una subclase en el mismo paquete que la superclase de lainstancia pueden sobrescribir cualquier método de la superclase que no estémarcado como private o final. Una subclase en un diferente paquete sólopuede sobrescribir los métodos no-finales marcados como public o protected(puesto que los métodos protected son heredados por la subclase).

El método que sobrescribe puede lanzar cualquier excepción unchecked, sinimportar si el método sobrescrito declara la excepción.

El método que sobrescribe no debe lanzar excepciones checked que sonnuevas o más amplias que las declaradas por el método sobrescrito. Porejemplo, un método que declara una FileNotFoundException no puede sersobrescrito por un método que declare una SQLException, Exception ocualquier otra excepción no-runtime a no ser que sea subclase deFileNotFoundException.

El método que sobrescribe puede lanzar excepciones más específicas ocerradas. Esto es porque que un método sobrescrito "tome riesgos" no significaque la excepción de la subclase tome los mismos riesgos. En definitiva: unmétodo que sobrescribe no tiene que declarar ninguna excepción que nuncavaya a lanzar, sin importar lo que el método sobrescrito declare.

No podemos sobrescribir un método marcado como final. No podemos sobrescribir un método marcado como static. Más adelante se

verán en más detalle los métodos estáticos. Si un método no puede ser heredado, no podemos sobrescribirlo. Recuerda

que sobrescribir implica que estamos re-implementando un método que hemosheredado. Por ejemplo, el siguiente código no es legal e incluso si añadimos elmétodo eat() a Horse, no sería una sobrescritura del método eat() de Animal.

Invocando una Versión de Superclase de un Método SobrescritoAlgunas veces, necesitaremos utilizar algún código de un método de la

Page 17: Oracle certified professional  java se 6 programmer 2

superclase, manteniendo la sobrescritura de dicho método para proporcionaralgún comportamiento adicional y específico. Esto se hace mediante la palabrareservada 'super' tal y como se muestra a continuación:

Nota: Usar 'super' para invocar a un método sobrescrito sólo se aplica a losmétodos de la instancia. (Los métodos estáticos no pueden sobrescribirse.)

Ejemplos de Sobrescritura de Métodos Legales e IlegalesVeamos cómo sobrescribir el método eat() de Animal:

La Tabla 2.1 muestra ejemplos de sobrescrituras ilegales del métdoeat() de Animaldada la definición anterior de la clase.Código Ilegal deSobrescritura Problema con el Código

privatevoideat() { } El modificador de acceso es másrestrictivo

public void eat() throwsIOException { }

Declara una excepción checked nodeclarada por la superclase

public void eat(String food) { } Sobrecarga legal, no sobrescritura (lalista de argumentos ha cambiado)

publicStringeat() { }No es sobrescritura (cambia tipo deretorno) ni sobrecarga (los argumentosno han cambiado)

Page 18: Oracle certified professional  java se 6 programmer 2

4.2. Métodos Sobrecargados

Los métodos sobrecargados nos permiten reutilizar el mismo nombre demétodo en una clase, pero con argumentos diferentes (y opcionalmente untipo de retorno diferente).Las reglas son simples:

Los métodos sobrecargados DEBEN cambiar la lista de argumentos Los métodos sobrecargados PUEDEN cambiar el tipo de retorno Los métodos sobrecargados PUEDEN cambiar el modificador de acceso Los métodos sobrecargados PUEDEN declarar excepciones checked nuevas o

más genéricas Un método puede ser sobrecargado en la misma clase o en una subclase. En

otras palabras, si la clase A define el método doStuff(int i), la subclase B podríadefinir un método doStuff(String s) sin sobrescribir la versión de la superclase.Los dos métodos, con el mismo nombre pero en diferentes clases, siguenconsiderándose sobrecargados si la subclase hereda una versión del método ydeclara otra versión sobrecargada en su definición de clase.

Sobrecargas LegalesVeamos el método que queremos sobrecargar:

Los siguientes métodos son sobrecargas legales del método:

Invocando Métodos SobrecargadosCuando se invoca un método, podría existirmás de un método con el mismo nombre para el tipo de objeto que estamosusando para invocar el método. Para decidir cuál de los métodos invocar nosbasamos en los argumentos. Si no existe un método que encaje con losargumentos pasados el compilador se quejará porque no puede encontrarlo. Lossiguientes son ejemplos de invocaciones de métodos sobrecargados:

Page 19: Oracle certified professional  java se 6 programmer 2

En el código de TestAdder anterior, la primera llamada a a.addThem(b,c) pasa dosenteros al método, por lo que se llama a la primera versión (la versiónsobrecargada que toma dos argumentos enteros). La segunda llamada aa.addThem(22.5, 9.3) pasa dos 'doubles' al método, por lo que se llama a lasegunda versión.

Invocar métodos sobrecargados que toman referencias a objetos en lugar devalores primitivos es más interesante. Digamos que tenemos un métodosobrecargado con una versión que toma un Animal y otra que toma unHorse(subclase de Animal). Si pasamos un objeto Horse en la invocación delmétodo, invocaremos la versión sobrecargada que toma un Horse. O esto es loque parece a primera vista:

Page 20: Oracle certified professional  java se 6 programmer 2

La salida es lo que esperábamos:in the Animal versionin the Horse version

Pero, ¿que pasa si usamos una referencia Animal que apunte aun objeto Horse?

El código anterior imprimiría:in the Animal versión

Aun cuando el objeto actual en ejecución es un Horse y no un Animal, la elecciónde cuál método sobrecargado se va a llamar NO se decide dinámicamente enejecución. Simplemente hay que recordar que el tipo de referencia (no el tipo deobjeto) es el que decide que método sobrecargado va a invocarse. En resumen,la versión sobrecargada del método que se va a llamar (de qué clase en elárbol de herencia) se decide en tiempo de ejecución basándose en el tipo deobjeto, pero qué versión sobrecargada del método se va a llamar se basa enel tipo de referencia del argumento pasado en tiempo de compilación. Siinvocamos un método pasándole una referencia de Animal que apunta a un objetoHorse, el compilador sólo sabe del Animal, por lo que elige la versiónsobrecargada que toma un Animal. No se preocupa de que en ejecución se estépasando un Horse.

Page 21: Oracle certified professional  java se 6 programmer 2

4.3. Polimorfismo en Métodos Sobrescritos y SobrecargadosEl polimorfismo no se preocupa si un método está sobrecargado. Si pasamos unareferencia de tipo Animal, el método sobrecargado que toma un Animal es el quese invoca, aunque el objeto actual sea un Horse. Por lo tanto, el polimorfismo nodetermina qué versión sobrecargada se invoca.

El polimorfismo entra en juego cuando la decisión es qué versión sobrescrita de unmétodo se va a llamar. No obstante, a veces, un método está sobrecargado ysobrescrito. Imaginemos que las clases Animal y Horse son las siguientes:Observa que la clase Horse tiene el método eat() sobrecargado y sobrescrito.

La siguiente tabla muestra qué versión de los tres métodos eat() se invocará enfunción de cómo son invocados.

MethodInvocationCode ResultAnimal a = new Animal();a.eat(); Generic Animal EatingGenerically

Horse h = new Horse();h.eat(); Horseeating hay

Animal ah = new Horse ();ah.eat();

Horse eating hay. Polymorphism works—the actualobject type (Horse), not the reference type (Animal),is used to determine which eat() is called.

Horse he = new Horse();he.eat("Apples") ;

Horse eating Apples. The overloaded eat(String s)method is invoked.

Animal a2 = new Animal();a2.eat ("treats");

Compier error! Compiler sees that Animal classdoesn't have an eat() method that takes a String.

Animal ah2 = new Horse();ah2.eat("Carrots");

Compiler error! Compiler still looks only at thereference, and sees that Animal doesn't have aneat() method that takes a String. Compiler doesn'tcare that the actual object might be a Horse atruntime.

Método Sobrecargado Método SobrescritoArgumento(s) Debe cambiar No debe cambiar

Tipo deRetorno Puede cambiar

No puede cambiarexcepto para retornoscovariantes

Excepciones Puede cambiar

Puede ser másespecífica. No debelanzar excepcioneschecked nuevas o másgenéricas

Acceso Puede cambiar No puede hacerse más

Page 22: Oracle certified professional  java se 6 programmer 2

restrictivo (pero símenos).

Invocación

El tipo de referencia determina qué versiónsobrecargada se selecciona (basándose enlos tipos de argumento). Ocurre en tiempode compilación. El método actual que esinvocado es una invocación virtual demétodo que ocurre en tiempo de ejecución,pero el compilador conocerá la signaturadel método.

El tipo de objeto (el tipode la instancia actualen pila) determina quémétodo se selecciona.Ocurre en tiempo deejecución.

5. Objetivo de Certificación 5.2 - Casting a Variables de ReferenciaDado un escenario, desarrollar código que demuestra el uso del polimorfismo. Esmás, determinar cuándo es necesario hacer un casting y reconocer errores decompilador y de tiempo de ejecución relacionados con el casting a referencias deobjetos.

Hemos visto cómo es posible y común usar tipos de variables de referenciagenéricos para referirnos a tipos de objetos más específicos. Por ejemplo, lasiguiente línea:

Pero qué ocurre cuanto queremos usar una variable de referencia Animal parainvocar un método que sólo tiene la clase Dog. Sabemos que la variable apunta aun Dog y queremos hacer algo específico de Dog. En el siguiente código, tenemosun array de Animal y siempre que encontremos un Dog en el array, querremoshacer algo específico de dicha clase.Por ahora haremos como si todo el código estuviera correcto, excepto en la líneadel código que invoca el método playDead.

Page 23: Oracle certified professional  java se 6 programmer 2

Cuando intentamos compilar este código, el compilador dice algo parecido a losiguiente: cannotfind symbol

El compilador quiere decir, "Hey, la clase Animal no tiene el método playDead()".Modifiquemos el bloque de código if:

El nuevo y mejorado bloque de código contiene un casting, que en este caso aveces es llamado downcast puesto que está haciendo un casting bajando sobre elárbol de herencia a una clase más específica. Ahora el compilador no poneproblemas. Le estamos diciendo "Sabemos que estamos apuntando a un objetoDog, por lo que es correcto hacer una nueva variable de referencia Dog paraapuntar a dicho objeto". En este caso estamos seguros puesto que antes de hacerel casting hacemos una prueba con instanceof para estar seguros.

Es importante conocer que el compilador está forzado a confiar en nosotroscuando hacemos un downcast, incluso cuando nos equivocamos:

Page 24: Oracle certified professional  java se 6 programmer 2

El código anterior compila pero cuando intentamos ejecutarlo obtenemos unaexcepción como la siguiente:java.lang.ClassCastException

Todo lo que puede verificar el compilador es que los dos tipos están en el mismoárbol de herencia.El compilador debe permitir cosas que es posible que no funcionen en tiempo deejecución. Sin embargo, si el compilador sabe a ciencia cierta que el castingpodría no funcionar, la compilación fallará. El siguiente bloque de código NOcompilará:

En este caso, obtendremos un error parecido al siguiente:inconvertibletypes

Al contrario que el downcasting, el upcasting (casting por encima del árbol deherencia hacia un tipo más general) trabaja de forma implícita (no es necesariohacerlo) puesto que cuando hacemos un upcasting estamos restringiendoimplícitamente el número de métodos que podemos invocar, al contrario quedowndcasting que implica que más tarde podríamos querer invocar un métodomás específico. Porejemplo:

Ambos upcasting compilarán y se ejecutarán sin lanzar excepciones, puesto queDos IS-A Animal. Todo lo que puede hacer un Animal puede hacerlo un Dog.

Page 25: Oracle certified professional  java se 6 programmer 2

El compilador y la JVM lo saben, por lo que el upcasting implícito siempre es legal.Si Dog implementa Pet y Pet define el método beFriendly(), entonces a un Dog lepodemos hacer un casting implícito a Pet, pero el único método que podremosinvocar es beFriendly(), que Dog se ha visto obligado a definir al implementar lainterfaz Pet.

Si Dog implementa Pet y Beagle extiende a Dog pero no declara que implementaa Pet, Beagle sigue siendo un Pet. La clase Beagle puede sobrescribir cualquiermétodo que hereda de Dog, incluyendo métodos que Dog ha implementado paracumplir con el contrato de la interfaz Pet.

Por último, si Beagle no declara que implementa Pet, al observar la API de Beaglepuede verse claramente que Beagle IS-APet, sin tener que buscar entre lassuperclases de Beagle. De forma resumida, si Beagle IS-A Dog y Dog IS-A Pet,entonces Beagle IS-A Pet. Por tanto, no podemos dejarnos engañar por un códigoque muestre una clase concreta que declara que implementa a una interfaz peroque no implementa los métodos de la interfaz. Antes de decir si el código es legal,debemos conocer si las superclases de esta clase están declaradas. Si algunaclase en su árbol de herencia proporciona implementaciones concretas (noabstractas) del método y han declarado que ella (la superclase) implementa lainterfaz, entonces la subclase no está en la obligación de re-implementar(sobrescribir) dichos métodos.

6. Objetivo de Certificación 1.2 - Implementando una InterfazDesarrollar código que declare una interfaz

Cuando implementamos una interfaz, estamos de acuerdo en cumplir con elcontrato definido en la interfaz. Esto significa que vamos a proporcionarimplementaciones legales para cada método definido y que cualquiera queconozca los métodos de la interfaz (no como se implementan sino coomo puedenllamarse y qué devuelven) pueden invocar dichos métodos en una instancia denuestra clase implementadora.

Java comprueba esto mediante una comprobación del compilador en todas lasclases que implementen una interfaz. Si la clase especifica que implementa unainterfaz, el compilador comprobará que tiene una implementación correcta porcada método en la interfaz (con algunas excepciones que se verán acontinuación).

Asumamos una interfaz, Bounceable , con dos métodos: bounce() ysetBounceFactor(). La siguienteclasecompilará:

Page 26: Oracle certified professional  java se 6 programmer 2

Evidentemente, esta implementación es de las peores que existen, sin embargocompila y se ejecuta. El contrato de la interfaz garantiza que la clase tendrá elmétodo pero nunca garantiza una buena implementación ni siquiera código deimplementación en el cuerpo del método.

Las clases implementadoras deben seguir las mismas reglas que laimplementación de un método en una clase que extiende a otra claseabstracta. Para que una clase implementadora sea legal, una clase no-abstracta debe hacer lo siguiente:

Proporcionar implementaciones concretas (no abstractas) para todos losmétodos declarados en la interfaz.

Seguir todas las reglas para sobrescrituras legales. Declarar excepciones no checked en los métodos de implementación

distintas a las declaradas por el método de la interfaz, o excepcionessubclases de las declaradas por el método de la interfaz.

Mantener la signatura del método de la interfaz y el mismo tipo de retorno(o un subtipo). Aunque no tiene que declarar las excepciones declaradas enel método de la interfaz.

Además, una clase implementadora puede ser abstracta. Por ejemplo, lo siguientees legal para una clase Ball que implementa Bounceable:

Esta clase no proporciona la implementación de los métodos pero es correcta. Sila clase es abstracta, puede simplemente pasar la tarea a su primera subclaseconcreta. Por ejemplo, si la clase BeachBall extiende a Ball y BeachBall no esabstracta, entonces deberá proporcionar implementaciones para todos losmétodos de Bounceable:

Puede haber clases que implementen interfaz pero no proporcionenimplementaciones correctas. Sin embargo, a no ser que la clase sea abstracta, laclase implementadora debe proporcionar implementaciones para todos losmétodos definidos en la interfaz.

Dos reglas más que debemos saber antes de aparcar este tema:

Page 27: Oracle certified professional  java se 6 programmer 2

1. Una clase puede implementar más de una interfaz. Es legal, por ejemplo, losiguiente:

Nosotros sólo podemos extender una clase, pero implementar muchasinterfaces. Recuerda que al ser subclase definimos quién y qué somos,mientras que implementar una interfaz define el papel que podemos jugar, apesar de lo diferentes que podrían ser otras clases que implementan lamisma interfaz (pero de diferente árbol de herencia).

Por ejemplo, una clase Person extiende a HumanBeing (aunque para algunos seadiscutible). Pero Person podría implementar Programmer, Snowboarder,Employee, Parent o PersonCrazyEnoughToTakeThisExam.

2. Una interfaz puede extender otra interfaz pero nunca implementar ninguna. Elsiguiente código es perfectamente legal:

Esto significa que: la primera clase implementadora concreta (no-abstracta) deBounceable debe implementar todos los métodos de Bounceable más todoslos de Moveable.

La subinterfaz, como la llamaremos, simplemente añade más requisitos al contratode la superinterfaz. Para las clases, lo siguiente es ilegal:public class Programmer extends Employee, Geek { } // Illegal !

Como hemos mencionado antes, una clase no puede extender múltiples clases enJava. Sin embargo, una interfaz es libre de extender múltiples interfaces.

Page 28: Oracle certified professional  java se 6 programmer 2

En el siguiente ejemplo, Ball debe implementar Bounceable, mas todos losmétodos de la interfaz que extiende Bounceable (incluyendo cualquier interfaz quedicha interfaz extienda y así hasta alcanzar el tope de la pila). Por lo que Balltendría que tener el siguiente aspecto:

Si la clase Ball no implementa alguno de los métodos de Bounceable, Moveable oSpherical, el compilador se quejará hasta que lo haga. A no ser que la clase Ballsea marcada como abstracta. En este caso, Ball podría elegir implementar alguno,todos o ninguno de los métodos de cualquiera de las interfaces y así dejar el restode las implementaciones a una subclase concreta de Ball, tal y como se muestra acontinuación:

7. Objetivo de Certificación 1.5 - Tipos de Retorno LegalesDado un código de ejemplo, determinar si un método está sobrescribiendo osobrecargando correctamente otorméotodo e identificar valores de retorno legales(incluyendo retornos covariantes ) para el método.

7.1. Declaraciones de Tipos de RetornoTipos de Retorno en Métodos SobrecargadosRecuerda que la sobrecarga demétodos no es más que reutilizar el nombre. El método sobrecargado es unmétodo diferente de cualquier otro método con el mismo nombre. Por lo que si

Page 29: Oracle certified professional  java se 6 programmer 2

heredamos un método y lo sobrecargamos en una subclase, no estamos sujetos alas restricciones de sobrescribir, lo que significa que podemos declarar cualquiertipo de retorno que queramos.Lo que no podemos hacer es cambiar únicamente el tipo de retorno.Recuerda que para sobrecargar un método debemos cambiar la lista deargumentos. El siguiente código muestra un método sobrecargado:

La versión Bar usa un tipo de retorno diferente. Esto es correcto puesto quehemos cambiado la lista de argumentos. Lo siguiente NO está permitido:

Sobrescritura y Tipos de Retorno y Retornos Covariantes.

Cuando una subclase quiere cambiar la implementación de un método heredado(sobrescritura), la subclase debe definir un método que encaje de forma exactacon la versión heredada. O, a partir de Java 5, podemos cambiar el tipo deretorno en el método que sobrescribe por un subtipo del tipo de retornodeclarado en el método sobrescrito (el de la superclase).Veamos un retornocovariante en acción:

Page 30: Oracle certified professional  java se 6 programmer 2

A partir de Java 5, este código compilará. Si intentamos compilar este código conun compilador 1.4 o con la bandera 'source' como sigue:javac -source 1.4 Beta.java

Obtendremos un error de compilador como el siguiente:attempting to use incompatible return type.

Para el examen, debemos estar seguros de que los métodos sobrecargadospueden cambiar el tipo de retorno, pero al sobrescribir métodos sólo lopodemos hacer siguiendo los retornos covariantes. Sólo este conocimientonos ayudará en muchas preguntas de examen.

7.2. Devolver un ValorSólo tenemos que recordar seis reglas al devolver un valor:

1. Podemos devolver null en un método con una referencia a un objeto como tipode retorno.

2. Un array es un tipo de retorno perfectamente legal.

3. En un método con un tipo de retorno primitivo, podemos devolver cualquiervalor o variable que pueda ser implícitamente convertida al tipo de retornodeclarado.

4. En un método con un tipo de retorno primitivo, podemos devolver cualquiervalor o variable al que le podamos hacer explícitamente un casting al tipo deretorno declarado:

5. No podemos devolver nada desde un método con un tipo de retorno 'void'.

Page 31: Oracle certified professional  java se 6 programmer 2

6. En un método con un tipo de retorno 'referencia a objeto', podemos devolvercualquier tipo de objeto al que se le pueda hacer implícitamente un casting al tipode retorno declarado.

8. Objetivos de Certificación 1.6 y 5.4 - Constructores e Instanciación1.6 - Dado un conjunto de clases y superclases, desarrollar constructores para unoo más clases. Dada la declaración de una clase, determinar si un constructor pordefecto será creado, y si es así, determinar el comportamiento de dichoconstructor. Dada una lista de clases internas y no.internas, escribir código parainstanciar la clase.

5.4 - Dado un escenario, desarrollar código que declare y/o invoque métodossobrescritos y sobrecargados y código que declare y/o invoce constructores de lasuplerclase, sobrescritos o sobrecargados.

8.1. Conceptos Básicos de los ConstructoresCada clase, incluyendo las clases abstractas, DEBEN tener un constructor.Un constructor tiene el siguiente aspecto:

Como se ve, no hay tipo de retorno. Recordar dos puntos claves sobre losconstructores:

No tiene tipo de retorno El nombre debe coincidir exactamente con el nombre de la clase

Page 32: Oracle certified professional  java se 6 programmer 2

Los constructores se utilizan para inicializar el estado de las variables deinstancia, como se muestra a continuación:

En el código anterior, la clase Foo no tiene un constructor sin argumentos. Estosignifica que el siguiente código no compilará:

Pero este otro código si compilará:

Por lo que es muy común (y deseable) que una clase tenga un constructor sinargumentos, independientemente de cuantos otros constructores sobrecargadostiene la clase (sí, los constructores pueden sobrecargarse). No siempre podremoscumplir con esto, ocasionalmente tendremos una clase donde no tiene sentidocrear una instancia sin aportar información al constructor.

8.2. Encadenado ConstructoresSabemos que los constructores se invocan en tiempo de ejecución cuandousamos el operador 'new':

¿Pero qué es lo que ocurre realmente?(Asumiremos que Horse extiende Animal y Animal extiende Object)

1. El constructor Horse es invocado. Cada constructor invoca el constructor desu superclase con una llamada implícita a 'super()', a no ser que elconstructor invoque un constructor sobrecargado de la misma clase (acontinuación se ampliará esto).

2. Se invoca el constructor de Animal.3. Se invoca el contructor de Object (Object es la última suplerclase de todas

las clases, por lo que no escribiremos 'extendsObject', esto es implícito). Eneste punto, estamos elel principio de la pila.

4. Las variables de instancia toman sus valores explícitos. Por valoresexplícitos entendemos valores que son asignados en el momento que se

Page 33: Oracle certified professional  java se 6 programmer 2

declaran las variables, como 'int x = 27', donde '27' es el valor explícito (enoposición al valor por defecto) de la variable de instancia.

5. Se completa el constructor de Object.6. La variables de instancia de Animal toman sus valores explícitos (si

tuvieran).7. Se completa el constructor de Animal.8. La variables de instancia de Horse toman sus valores explícitos (si

tuvieran).9. Se completa el constructor de Horse.

La siguiente tabla muestra cómo trabajan los constructores en la pila de llamadas:4. Object()3. Animal() callssuper()2. Horse() callssuper()1. main() calls new Horse()

8.3. Reglas para los ConstructoresLa siguiente lista resume las reglas que necesitamos saber para el examen (y paracomprender el resto de la sección). DEBEMOS recordarlas y estudiarlas más deuna vez:

Los constructores pueden usar cualquier modificador de acceso. Esto significaque sólo el código de dentro de la clase puede instanciar un objeto de dichotipo, por lo que si queremos permitir el uso de una instancia de la clase, lapropia clase debe proporcionar un método o una variable estática para permitirel acceso a una instancia creada en el cuerpo de la clase).

El nombre del constructor debe coincidir con el nombre de la clase. Los constructores no tienen tipo de retorno. Es legal (pero estúpido) tener un método con el mismo nombre de la clase,

pero esto no lo convierte en un constructor. Si vemos el tipo de retorno, es unmétodo y no un constructor. De hecho, podríamos tener un método y unconstructor con el mismo nombre -el nombre de la clase- en la misma clase yno sería un problema para Java. Ten cuidado de no confundir un método conun constructor, debemos mirar el tipo de retorno.

Si no escribimos un constructor en nuestro código de clase, se generará unconstructor por defecto por el compilador.

El constructor por defecto SIEMPRE es un constructor sin argumentos. Si queremos tener un constructor por defecto y hemos escrito otro/s

constructor/s en nuestro código de clase, el compilador no proporcionará unconstructor sin argumentos (o cualquier otro constructor). Dicho de otra forma,si hemos escrito un constructor con argumentos, no tendremos un constructorsin argumentos a no ser que lo escribamos nosotros.

Cada constructor tiene, como primera sentencia, una llamada a un constructorsobrecargado (this()) o una llamada al constructor de la superclase (super()),aunque recuerda que esta llamada puede ser insertada por el compilador.

Page 34: Oracle certified professional  java se 6 programmer 2

Si escribimos un constructor (en lugar de confiar en el constructor por defectogenerado por el compilador) y no escribimos una llamada a super() o a this(), elcompilador insertará una llamada sin argumentos a super(), como primerallamada en el constructor.

Una llamada a super() puede ser una llamada sin argumentos o puede incluirargumentos pasados al super constructor.

Un constructor sin argumentos no es necesariamente el constructor por defecto(por ejemplo proporcionado por el compilador), aunque el constructor pordefecto siempre es un constructor sin argumentos. El constructor por defectoes el que proporciona el compilador. Nosotros somos libres de crear nuestropropio constructor sin argumentos.

No podemos hacer una llamada a un método de instancia, o acceder a unavariable de instancia, hasta que se haya ejecutado el super constructor.

Sólo podemos acceder a métodos y variables estáticos como parte de lallamada a super() o this().

Las clase abstractas tiene constructores y dichos constructores siempre sonllamados cuando se instancia la subclase concreta.

Las interfaces no tienen constructores. Las interfaces no son parte del árbol deherencia de un objeto.

La única forma de invocar un constructor es desde otro constructor. En otraspalabras, no podemos escribir código que llame a un constructor tal y como semuestra a continuación:

8.4. Determinar si será Creado un Constructor por DefectoEl siguiente ejemplo muestra una clase Horse con dos constructores:

¿Pondrá un constructor por defecto el compilador en la clase anterior?. No!, ¿y enla siguiente variación?

Page 35: Oracle certified professional  java se 6 programmer 2

Ahora el compilador, ¿insertará un constructor por defecto?. No!, ¿y en lasiguiente clase?

Ahora el compilador generará un constructor por defecto para la clase anterior,puesto que la clase no ha definido constructores. Veamos la siguiente:

Podría parecer que el compilador no creará ninguna, puesto que hay unconstructor en la clase Horse. ¿O no es así?, echemos otro vistazo a la claseanterior. ¿Qué hay incorrecto en el constructor Horse()?. Resulta que no es unconstructor. Simplemente es un método que tiene el mismo nombre que la clase.Recuerda que el tipo de retorno es un signo inequívoco de que estamos viendo unmétodo y no un constructor.

8.5. ¿Cómo Podemos Saber el Aspecto del Constructor por Defecto?Por lo siguiente: El constructor por defecto tiene el mismo modificador de acceso que la clase. El constructor por defecto no tiene argumentos. El constructor por defecto incluye una llamada sin argumentos al super

constructor (super()).

La siguiente tabla muestra qué generará (y qué no) para nuestra clase.Código de Clase (lo queescribimos)

Código de Constructor Generado por elCompilador (en negrita)

classFoo { }classFoo {Foo() { super ( ) ; }}

classFoo {Foo() { }}

classFoo {Foo() { super() ; }}

publicclassFoo { }class Foo {public Foo() { super(); }}

class Foo {Foo(String s) { }}

class Foo {Foo (String s) { super(); }}

class Foo {Foo(String s) { super(); }}

Nada, el compilador no necesita insertar nada.

classFoo { classFoo {

Page 36: Oracle certified professional  java se 6 programmer 2

voidFoo() { }}

voidFoo() { }Foo() { super(); }}

(voidFoo() es un método, no un constructor.)

8.6. ¿Qué Ocurre si el Super Constructor tiene Argumentos?Los constructores pueden tener argumentos como los métodos y si intentamosinvocar un método que toma, por ejemplo, un entero pero no le pasamos nada almétodo, el compilador se quejará tal y como se muestra a continuación:

El compilador se quejará de que no podemos invocar el método sin pasarle unentero. Sin embargo, el compilador podría lanzar un mensaje dudoso en algunasversiones de la JVM:UseBar.java:7: takeInt(int) in Bar cannot be applied to()b.takeInt();

^La última línea es la que debería encajar con el método. Y por encajar, queremosdecir que los tipos de argumentos deben ser capaz de aceptar los valores ovariables que le estamos pasando y en el orden que se los pasamos. Losconstructores trabajan de la misma forma.

Por lo que si nuestro super constructor (el constructor de la inmediata superclarse)tiene argumentos, deberíamos aportar en la llamada a super() los argumentosapropiados. Aquí hay un punto crucial: si nuestra superclase no tiene unconstructor sin argumentos, debemos escribir un constructor en nuestra clase(sublcase) puesto que necesitamos un lugar donde colocar la llamada a super conlos argumentos apropiados.

Page 37: Oracle certified professional  java se 6 programmer 2

A continuación se muestra un ejemplo del problema:

Una vez más el compilador lanza un mensaje dudoso:Horse.java:7: cannot resolve symbolsymbol : constructor Animal ()location: class Animalsuper(); // Problem!^Si somos afortunados nuestro compilador podría ser un poco más explícito. Perode nuevo, el problema es que no existe nada que encaje con lo que intentamosejecutar -un constructor de Animal sin argumentos.

Otra forma de decir esto es que nuestra superclase no tiene un constructor sinargumentos, por lo que en nuestra subclase no podemos usar el constructor pordefecto aportado por el compilador. Así de simple.Puesto que el compilador sólo puede poner en una llamada la invocación a super()(sin argumentos), no seremos capaces de compilar algo parecido a lo siguiente:

Si intentamos compilar este código obtendremos el mismo error que cuandoponemos un constructor en la subclase con una llamada a la versión sinargumentos de super():Clothing.java:4: cannot resolve symbolsymbol : constructor Clothing ()location: class Clothing

classTShirtextendsClothing { }^

Page 38: Oracle certified professional  java se 6 programmer 2

De hecho, el código anterior es implícitamente el mismo que el siguiente:

Un último apunte sobre los constructores por defecto (y probablemente muyobvio), los constructores nunca se heredan. No son métodos. No pueden sersobrescritos (puesto que no son métodos y sólo los métodos de instancia puedensobrescribirse). Por lo que el/los tipos de constructores de nuestra superclase nodetermina de ninguna forma el tipo de constructor por defecto que obtendremos.Algunas personas creen equivocadamente que el constructor por defecto encajade alguna forma con el super constructor, bien en los argumentos que tendrá elconstructor por defecto (recuerda que el constructor por defecto es siempre sinargumentos) o en la llamada a super() aportada por el compilador.

Por tanto, aunque los constructores no pueden ser sobrescritos, hemos visto quepueden ser sobrecargados.

8.8. Constructores SobrecargadosSobrecargar un constructor significa escribir múltiples versiones del constructor,cada una con una lista diferente de argumentos como los siguientes ejemplos:

La clase Foo anterior tiene dos constructores sobrecargados, uno toma un String yel otro nada. Puesto que no hay código en la versión sin argumentos, es idénticaal constructor por defecto que proporciona el compilador, pero recuerda que si hayalgún constructor en la clase, el compilador no proporcionará un constructor pordefecto. Si queremos un constructor sin argumentos, además de una versiónsobrecargada con argumentos, debemos escribirlo nosotros, como en el ejemploanterior.

Sobrescribir un constructor se usa normalmente para proporcionar formasalternativas a los clientes para instanciar objetos de nuestra clase. Por ejemplo, si

Page 39: Oracle certified professional  java se 6 programmer 2

el cliente conoce el nombre del animal, puede pasarlo al constructor que toma unString. Pero si no lo conoce, llamará al constructor sin argumentos y dichoconstructor proporcionará un nombre por defecto. Veámoslo:

Al ejecutar el código cuatro veces obtendremos la siguiente salida:% java AnimalGigiZeus% java AnimalFluffyZeus% java AnimalRoverZeus% java AnimalFluffyZeus

La siguiente tabla muestra la pila de llamadas para las invocaciones deconstructores cuando se sobrecarga un constructor. Luego veremos la explicacióndel código.4 Object3 Animal(Strings s) calls Super()2 Animal() callsthis(randomlyChosenNameString)1 main() calls new Animal()

En lugar de llamar a super(), estamos llamando a this() y this() siempre significauna llamada a otro constructor de la misma clase. Tarde o temprano siempre sellamará al constructor super(), sólo lo estamos retrasando. Algún constructor, en

Page 40: Oracle certified professional  java se 6 programmer 2

algún lugar, deberá llamar a super().Concepto Clave: La primera línea en un constructor DEBE ser una llamada asuper() o una llamada a this().

No hay excepciones. Si no hacemos dichas llamadas en nuestro constructor, elcompilador insertará una llamada sin argumentos a super(). Un constructor nuncatendrá una llamada a super() y una llamada a this(). Cada una de esas llamadasdeberían ser la primera sentencia en un constructor. Esto implica que elcompilador no pondrá una llamada a super() en el constructor que tenga unallamada a this().Veamos un código de ejemplo:

El compilador podría no detectar el problema, el asume que sabemos lo queestamos haciendo. El problema es que dado que un super constructor siempredebe llamarse. Recordemos que el compilador no pone un constructor por defectosi ya tenemos alguno. Y cuando el compilador no pone un constructor por defecto,inserta una llamada a super() en cualquier constructor que no tenga una llamadaexplícita al super constructor -a no ser que el constructor tenga una llamada athis(). Por lo que en el código anterior obtendríamos un bucle infinito y la pila sesobrecarga obteniendo un:% java AException in thread "main" java.lang.StackOverflowError

El beneficio de tener constructores sobrecargados es que ofrecemos formasflexibles de instanciar objetos de nuestra clase. Los beneficios de tener unconstructor que invoque a otro sobrecargado es evitar la duplicación de código.Básicamente, cada uno de los otros constructores "no reales" llamarán a otroconstructor sobrecargado, pasándole lo que necesite.

9. Objetivo de Certificación 1.3 – EstáticosDesarrollar código que declare, inicialize y use tipos primitivos, enumerados,arrays y objetos como estáticos, de instancia y como variables locales. Ademas,usar identificadores legales para los nombres de variables.

9.1. Métodos y Variables EstáticosPara comprender cómo funcionan los miembros estáticos, veamos una razón parausarlo. Imaginemos que tenemos una clase de utilidad que dispone de un métodoque siempre se ejecuta de la misma forma, por ejemplo devolver un númeroaleatorio. No importa la instancia de la clase que realiza el método, siempre se

Page 41: Oracle certified professional  java se 6 programmer 2

comportará igual. Dicho de otra forma, el comportamiento del método no tienedependencia con el estado (valores de variables de instancia) de un objeto.

Los métodos y variables estáticos siguen a la clase y no a una instancia enparticular. De hecho, podemos usarlos sin necesidad de tener una instancia dedicha clase, sólo necesitamos tener accesible la clase. Si hubiera instancias, unavariable estática de una clase se compartirá por todas las instancias de la clase.

El siguiente código declara y usa una variable estática contador:

En el código anterior, la variable frogCount se pone a 0 cuando se carga porprimera vez la clase en la JVM, antes de que se cree cualquier instancia (aunqueno sería necesario inicializarla puesto que toman el mismo valor por defecto que sise tratara de variables de instancia). Siempre que se crea una instancia de Frog,el constructor se ejecuta e incrementa la variable contador. El resultado de laejecución del código anterior es el siguiente:Frogcountisnow 3

Ahora imaginemos qué hubiera pasado si la variable fuera una variable deinstancia:

Cuando se ejecuta este código, debería seguir creando las tres instancias de Frog,¡pero el resultado es un error de compilador!. No podemos compilar este código ymucho menos ejecutarlo.

Page 42: Oracle certified professional  java se 6 programmer 2

Frog.java:11: non-static variable frogCountcannot be referencedfrom astaticcontextSystem.out.println("Frog count is " + frogCount);^

1 error

El problema es que main() es un método estático y por tanto no se estáejecutando contra una instancia de la clase particular. Un método estático nopuede acceder a una variable no-estática (de instancia), puesto que no es unainstancia. Esto no quiere decir que no haya objetos en la pila, sino que el métodoestático no sabe nada de ellos. Lo mismo se aplica a los métodos de instancia,uno estático no puede invocar directamente un método no-estático. Es decir,estático = clase, no-estático = instancia.

9.2. Accediendo a Métodos y Variables EstáticosYa sabemos que no necesitamos una instancia para invocar miembros estáticos,pero entonces ¿cómo invocarlos?, ¿cuál es la sintaxis?. Sabemos que para unmétodo de instancia usamos el operador punto sobre una instancia:

En el código anterior, instanciamos un Frog, lo asignamos a la variable dereferencia f y luego usamos la referencia para invocar un método de la instanciade Frog que hemos creado.

Esto no debe aplicarse para acceder a un método estático, puesto que podría nohaber instancias de la clase. Por tanto, la forma de acceder a un método estático(o variable estática) es usar el operador punto sobre el nombre de la clase, tal ycomo se muestra a continuación:

Page 43: Oracle certified professional  java se 6 programmer 2

El lenguaje Java también nos permite usar una variable de referencia a objetopara acceder a un miembro estático:

En el código anterior, instanciamos un Frog, lo asignamos a la variable f y luegousamos dicha variable para invocar un método estático. Pero aunque estemosusando una instancia específica para acceder a un método estático, las reglas nohan cambiado. Es simplemente un truco de sintaxis, pero el miembro es invariablecon respecto a la instancia particular que usemos. En el ejemplo, el compiladorsólo se preocupa de que la variable de referencia sea declarada de tipo Frog.

Recordar que los métodos estáticos no pueden ser sobrescritos. Esto no significaque no puedan ser redefinidos en una subclase, pero redefinir y sobrescribir no eslo mismo. Vemoas un ejemplo de un méotodo estático redefinido (no sobrescrito):

La ejecución de este código produce la siguiente salida:aaa

Page 44: Oracle certified professional  java se 6 programmer 2

Recuerda, la sintaxis a[x].dostuff() es simplemente un comando directo, elcompilador lo sustituirá por algo como Animal.dostuff(). Observa que no hemosutilizado la mejora del bucle de Java 1.5.

10. Objetivo de Certificación 5.1 - Acoplamiento y CohesiónDesarrollar código que implemente una fuerte encapsulación, un bajoacoplamiento y una alta cohesión en clases, describiendo posteriormente losbeneficios.

Las definiciones del examen de Sun para la Cohesión y el Acoplamiento son unpoco subjetivas, por lo que en este capítulo se discutirán los términos desde laperspectiva del examen y no significa que sean La Única Definición Real de estosdos principios de diseño de OO.

En general, un buen diseño OO establece un bajo acoplamiento y evita un altoacoplamiento así como una alta cohesión, evitando una baja cohesión. Como lamayoría de las discusiones de diseño OO, los objetivos de una aplicación son:

Facilidad de creación Facilidad de Mantenimiento Facilidad de Mejoras

10.1. Acoplamiento: Acoplamiento es la cantidad de conocimiento que una clasetiene sobre otra. Si el único conocimiento que una clase A tiene sobre una clase Bes lo que B expone a través de su interfaz, entonces la clase A y la clase B estánbajamente acopladas, lo que es algo bueno.

Usando el segundo escenario, imaginemos que ocurrirá cuando se mejore la claseB. Es posible que el desarrollador de la mejora no sepa de la clase A. Eldesarrollador de B piensa que cualquier mejora que no rompa la interfaz de laclase debería ser segura, por lo que podría cambiar algunas partes de la clase queno pertenecen a la interfaz, lo que causaría que se rompiera la clase A.

En el extremo del espectro del acoplamiento es la horrible situación en el que laclase A conoce cosas que no son de la API de B y viceversa. Esto es MUY MALO.Si alguna de las clases se cambia, hay posibilidades de que la otra clase deje defuncionar. Veamos un ejemplo obvio de alto acoplamiento, que ha sido permitidopor una encapsulación pobre:

Page 45: Oracle certified professional  java se 6 programmer 2

Todas las aplicaciones OO no triviales son una mezcla de clases e interfacestrabajando juntas. De forma ideal, las interacciones entre objetos en un sistemaOO deberían ser mediante APIs, o contratos, de las distintas clases de objetos. Deforma teórica, si todas las clases de la aplicación tuvieran APIs bien diseñadas,debería ser posible que todas las interacciones usaran dichas APIs. Como hemosvisto antes en este capítulo, un aspecto de un buen diseño de clase y API es quelas clases deberían estar bien encapsuladas.

En el fondo, el acoplamiento es un concepto un poco subjetivo. Debido aesto, el examen nos probará en ejemplos realmente obvios de altoacoplamiento, no se nos preguntarán por llamadas sutiles.

10.2. CohesiónMientras que la cohesión trata sobre cómo interactúan las clases, la cohesión tratasobre cómo una única clase se diseña. El término cohesión se usa para indicar elgrado mediante el cual una clase tiene un único y bien enfocado propósito. Ten enmente que la cohesión es un concepto subjetivo. Enfocado a una clase, una altacohesión es una buena característica. El beneficio clave de alta cohesión es quelas clases son más fáciles de mantener (y suelen cambiar menos). Otro beneficioes que las clases con un propósito bien enfocado tiene a ser más reutilizables queotras clases.Veamos un ejemplo:

Page 46: Oracle certified professional  java se 6 programmer 2

Ahora imagina que nuestro jefe dice, "Los clientes han decidido que quierengenerar un informe de proyección de ingresos y también algún informe deinventario. Les gusta nuestras características de informes, pero quierenasegurarse de que dichos informes puedan ser enviados a una base de datos, unaimpresora y salvar los informes generados en ficheros de datos".

En lugar de poner todo el código de impresión en una clase de informe,probablemente sería mejor haber hecho el siguiente diseño desde el principio:

Este diseño es mucho más cohesivo. En lugar de tener una clase que haga todo,hemos dividido el sistema en cuatro clases principales, cada una con un papelmuy específico o cohesivo. Puesto que hemos construido estas clasesespecializadas y reutilizables, será mucho más fácil escribir un nuevo informe,puesto que tenemos una clase de conexión a base de datos, la clase para laimpresora y la clase para salvar el contenido en fichero. Esto significa que puedenreutilizarse por otras clases que quisieran imprimir un informe.

2. Orientación a Objetos

Guía para el Examen 2.1Observar el código que aparece con preguntas sobre el comportamiento de unmétodo, cuando el problema es realmente una falta de encapsulación. Observa elsiguiente ejemplo y veremos a qué nos referimos:

Page 47: Oracle certified professional  java se 6 programmer 2

Ahora consideremos esta pregunta: ¿El valor de la variable 'right' siempre va a serun tercio del valor de la variable 'left'?. Tiene pinta de que sí excepto por el hechode que los usuarios de la clase Foo no necesitan usar el método setLeft().Simplemente pueden cambiar directamente el valor de las variables a un valorentero arbitrario.

Guía para el Examen 2.2Si un método está sobrescrito pero usamos una referencia polimórfica (supertipo)para hacer referencia al objeto subtipo con el método que sobrescribe, elcompilador asume que estamos llamado a la versión supertipo del método. Si laversión supertipo declara una excepción checked, aunque no lo haga el métodoque la sobrescribe, el compilador sigue creyendo que estamos llamando a unmétodo que declara una excepción.Veamos un ejemplo:

Este código no compilará por la Excepción declarada en el método eat() de

Page 48: Oracle certified professional  java se 6 programmer 2

Animal. Esto ocurre siempre, aun cuando en tiempo de ejecución, el método eat()usado sea el de la versión Dog, que no declara la excepción.

Guía para el Exámen 2.3No te dejes engañar por un método que está sobrecargado pero no sobrescrito poruna subclase. Es perfectamente legal hacer lo siguiente:

La clase Bar tiene dos métodos doStuff(): la versión sin argumentos que hereda deFoo (y que no sobrecribe) y la versión sobrecargada dostuff (string s) definida enla clase Bar. Un código con una referencia a un Foo puede invocar sólo la versiónsin argumentos, pero si se trata de un Bar podría invocar cualquiera de lasversiones sobrecargadas.

Guía para el Exámen 2.4Los creadores del examen te dirán que están obligados a apretar mucho código enespacios pequeños "por el funcionamiento del examen". Aunque esto esparcialmente cierto, también les gusta liar.El siguiente código:

Puede ser reemplazado con esta otra forma comprimida:

En este caso, el compilador necesita todos esos paréntesis, de otra formapensaría que está manejando una sentencia incompleta.

Guía para el Exámen 2.5Buscar usos ilegales de extends e implements. A continuación se muestranejemplos de declaraciones legales e ilegales de clases e interfaces:

Page 49: Oracle certified professional  java se 6 programmer 2

Independientemente de lo que nos estén preguntando, el problema real de unapregunta podría estar en la declaración de la clase o interfaz. Antes de quedaratrapados en la traza de un flujo de hilos complejo, debemos comprobar si elcódigo compila. Seremos impresionados por el esfuerzo que ponen losdesarroladores del examen en distraernos del problema real.

Guía para el Exámen 2.6Buscar métodos que declaren un tipo de retorno que sea clase abstracta o interfazy saber que cualquier objeto que pase la prueba IS-A (dicho de otra forma, eloperador instanceofdevolerá true) puede ser devuelto desde dicho método, porejemplo:

Este código compilará, el valor de retorno es un subtipo.

Guía para el Exámen 2.7Uno de los principales misterios para los programadores Java novatos es cuandointentan acceder a una variable de instancia (no estática) desde el método estáticomain() (que no sabe nada de cualquier instancia y que, por lo tanto, no puedeacceder a la variable). El siguiente código es un ejemplo de acceso ilegal a unavariable no estática desde un método estático:

Page 50: Oracle certified professional  java se 6 programmer 2

Este código nunca compilará puesto que no podemos acceder a variables noestáticas desde un método estático. Por supuesto, el truco del examen es que lapregunta no será tan obvia como el código anterior. El problema puede estar enque no aparece tan claro. Por ejemplo, el código anterior podría quedar:

Por tanto, mientras que estamos intentando seguir la lógica, el problema real esque x e y no pueden ser usados en el cuerpo del método main(). Lo mismo seaplica al acceso a métodos no-estáticos desde un método estático. La regla es, unmétodo estátido de una clase no puede acceder a una variable o método deinstancia (no-estático) de su propia clase.