Está en la página 1de 66

SBADO, 5 DE NOVIEMBRE DE 2011

Sun Certified Java Programmer 6, CX-310-065 - Parte 2:


Orientacin a Objetos
En este segundo post para la certificacin de Java 6 hablaremos sobre conceptos de la orientacin
a objetos, que abarca temas como la herencia, el polimorfismo, la cohesin, bajo acoplamiento
(loose coupling), etc.

Empezaremos hablando sobre la encapsulacin:
Encapsulacin

La encapsulacin es un mecanismo que nos permite que, aunque nuestras clases utilicen muchas
variables y mtodos para su correcto funcionamiento, no todas sean visibles desde el exterior. O
sea que solo exponemos lo que los clientes necesitan para poder hacer uso de los objetos de
nuestra clase.

Para entender mejor este concepto imaginemos el siguiente escenario:

Tenemos la siguiente clase:

public class Examen
{
public String pregunta1;

public static void main(String... args)
{
Examen examen = new Examen();
examen.pregunta1 = "Que es Java?"; // Legal pero no
recomendable
}
}


El ejemplo anterior compilar y se ejecutar de forma correcta. Sin embargo no es recomendable
que los atributos de la clase (las variables de instancia) estn expuestas de forma que los
clientes puedan leer y escribir sus valores directamente. De esta forma cualquiera podra
colocar el valor que quisiera en la variable "pregunta1", an valores que nuestra aplicacin no
puede o no est preparada para manejar.

Ahora hagamos una pregunta: Cmo poder cambiar la clase cuando alguien cambia el valor de
"pregunta1" por un valor incorrecto? La nica forma es volver a la clase e implementar un mtodo
de slo escritura (un mtodo setter: "setPregunta1(String pregunta1)") y ocultar la variable
"pregunta1" establecindola como privada, pero de esta manera al no establecerla desde un
principio con los mtodos "set" o "get" todas las personas que han utilizado este cdigo
anteriormente y de la manera en la que estaba implementada se encontraran perdidas.

La capacidad de realizar cambios en el cdigo de aplicacin sin romper el cdigo de otras
personas que utilizan este cdigo es un beneficio clave de la encapsulacin. Ocultando los
detalles de la implementacin a travs de mtodos de acceso nos brinda la ventaja de poder
rehacer el cdigo dentro de los mtodos sin forzar a las dems personas a cambios, ya que
ellas usan dichos mtodos de acceso.

Con todo esto obtenemos las dos promesas/beneficios de la programacin orientada a objetos:
Flexibilidad y Mantenimiento, pero como vemos estos dos beneficios no llegan solos, nosotros
tenemos que implementar nuestro cdigo de manera que brinde y soporte estos beneficios.

Estas son algunas recomendaciones para lograr la encapsulacin:
Mantener las variables de instancia protegidas (mayormente con el modificador de acceso
private).
Mantener publicos los mtodos de acceso a las variables de instancia (modificador de
acceso public), as forzamos a llamar a las variables de instancia y a la implementacin del mismo
a travs de estos mtodos en lugar de ir directamente por las variables de instancia.
Para los mtodos de acceso se recomienda usar las reglas de las convenciones de
nombres de JavaBean:set<nombrePropiedad> y get<nombrePropiedad>, de las cuales se
habl en el post anterior.

A continuacin mostramos un ejemplo ms prctico de lo que nos estamos refiriendo:



La clase "A" no puede acceder a las variables de instancia de la Clase "B" sin antes ir a los
mtodos de acceso ("set" y "get") de dichas variables, las variables de instancia son marcadas
privadas y los mtodos de acceso son pblicos.

Debemos tener presente que el cdigo de estos mtodos no solo se utiliza para devolver o
establecer los valores de las variables de instancia, tambin se puede establecer lgica o
implementacin de muchas ms cosas o reglas que queramos definir, por ejemplo:

public void setTamanio(int tamanio)
{
this.tamanio = tamanio * 0.10;
this.color = "negro";
}



El encapsulamiento es uno de los mecanismos que nos proporciona la orientacin a objetos para
poder darle una funcionalidad rica a nuestras clases sin que las personas que las utilicen sepan los
detalles exactos de cmo est implementada dicha funcionalidad.

Sin embargo, este no es el nico mecanismo proporcionado por la orientacin a objetos. A
continuacin veremos otro de ellos. La herencia.

Herencia, ESUN, TIENEUN (ISA, HAS-A)

En Java, la herencia se encuentra en todos. Es seguro decir que en Java casi nada se puede
hacer sin hacer uso de la herencia. Para dar un ejemplo a continuacin usaremos del operador
"instanceof" (por ahora no ahondaremos mucho en la explicacin del uso de este operador ya
que se tocar ms adelante con mayor detalle, slo cabe recordar ahora que este operador
devuelve un "true" si la variable puesta al principio es del tipo de la variable con la que se est
comparando):

public class Test
{
public static void main(String... args)
{
Test t1 = new Test();
Test t2 = new Test();

if(!t1.equals(t2))
{
System.out.println("No son iguales")
}
if(t1 instanceof Object)
{
System.out.println("t1 es un objeto");
}
}
}


De dnde saca "t1" el mtodo "equals"? Si no hemos implementado ningn mtodo dentro de la
clase con ese nombre, o s? Por otro lado se pregunta si "t1" es una instancia de la clase
"Object" y de ser as, la condicin if ser exitosa.

Cmo puede ser "t1" del tipo "Object" si solo lo declaramos que sea del tipo de la clase
"Test"? Esto ocurre porque todas las clases en java (las que ya estn escritas, las que escribimos
y las que escribiremos) son una subclase de la clase "Object" (excepto por supuesto la clase
"Object" misma) y siempre tendrn mtodos como "equals", "clone", "notify", "wait" y otros
ms. Siempre que creamos una clase, esta hereda todos los mtodos de la clase "Object".

El mtodo "equals" por ejemplo: Los creadores de Java asumieron correctamente que nosotros
comnmente desearamos comparar instancias de las clases para comprobar la igualdad; si la
clase "Object" no tuviera un mtodo "equals" tendramos que implementar nosotros mismos un
mtodo para este propsito.

Tambin debemos recordar que las 2 razones ms importantes para el uso de la herencia son:
Reutilizacin de cdigo
Uso del polimorfismo

Empecemos con la reutilizacin. Un enfoque de diseo comn es crear una versin de una clase
bastante genrica y despus crear subclases muy especializadas que hereden de esta, por
ejemplo:

public class Animal
{
public void muevete()
{
System.out.println("Me estoy moviendo");
}
}


public class Perro extends Animal
{
public void ladra()
{
System.out.println("Estoy ladrando");
}
}

public class PruebaAnimal
{
public static void main(String... args)
{
Perro perro = new Perro();
perro.muevete();
perro.ladra();
}
}


La salida del cdigo anterior seria:

Me estoy moviendo
Estoy ladrando


Como podemos ver, la clase "Perro" est heredando el mtodo "muevete" de la clase "Animal" y
que tambin tiene su propio mtodo agregado, en este caso es el mtodo "ladra". Aqu se est
haciendo uso de la reusabilidad al utilizar un mtodo genrico de una clase padre que en este caso
es el mtodo "muevete", con esto podemos crear diferentes tipos de animales y todos van a poder
utilizar el mtodo "muevete" sin necesidad de implementarlo ellos mismos.

El segundo objetivo de la herencia es poder acceder a las clases polimrficamente. Imaginemos
este escenario: digamos que tenemos una clase llamada "Entrenador" que quiere recorrer todos
los diferentes tipos de animal e invocar al mtodo "muvete" en cada uno de ellos, al momento de
escribir la clase "Entrenador" no sabemos cuntas clases de "Animal" podra haber y seguro no
vamos a querer cambiar el cdigo slo porque a alguien se le ocurri crear un nuevo tipo
de Animal.

Lo bonito del polimorfismo es que podemos tratar cualquier tipo de "Animal" como un "Animal",
en otras palabras podemos decir lo siguiente: No me importa qu tipo de Animal se pueda crear,
siempre y cuando extienda (herede) de Animal todos van a poder moverse (mtodo "muevete").

Ahora miremos esto con un ejemplo:

public class Animal
{
public void muevete()
{
System.out.println("Me estoy moviendo");
}
}

public class Perro extends Animal
{
public void ladra()
{
System.out.println("Estoy ladrando");
}
}

public class Gato extends Animal
{
public void ronronea()
{
System.out.println("Estoy ronroneando");
}
}


Ahora imaginemos una clase llamada "Entrenador" que tiene un mtodo que tiene como
argumento un "Animal", esto significa que puede tomar cualquier tipo de "Animal", cualquier tipo
de animal puede ser pasado a un mtodo con un argumento del tipo "Animal", ejemplo:

public class Entrenador
{
public static void main(String... args)
{
Gato gato = new Gato();
Perro perro = new Perro();
mueveteAnimal(gato);
mueveteAnimal(perro);
}

public static void mueveteAnimal(Animal animal)
{
animal.muevete();
}
}


La salida del cdigo anterior es:

Me estoy moviendo
Me estoy moviendo



El mtodo "mueveteAnimal" est declarando un "Animal" como argumento pero se le puede
pasar cualquier sub-clase o sub-tipo de esta clase "Animal", este mtodo podra invocar a
cualquier mtodo dentro de la clase "Animal". Lo que si debemos de tener en cuenta es que slo
podemos llamar a los mtodos declarados por "Animal", los mtodos declarados dentro de las
subclases de "Animal" son dependiente del tipo declarado, esto significa que no podramos llamar
al mtodo "ladra" incluso si el "Animal" que se est pasando es del tipo "Perro".
RELACIONES IS A, HAS A

IS A

En Orientacin a objetos el concepto de "IS-A" (es-un) esta basado en la herencia de una clase
("extends") o en la implementacin de una interface ("implements"). IS-A es una forma de
decir "Esta cosa es del tipo de esta cosa" (o estos dos tipos pueden ser equivalentes), por ejemplo
un "Perro" es del tipo "Animal", en OO nosotros podemos decir: "Perro IS-A Animal",
"Lechuga IS-A Vegetal", en java podemos expresar esta relacin IS-A por medio de las
palabras reservadas "extends" (para la herencia de clases) y de "implements" (para la
implementacin de interfaces), veamos un ejemplo:

public class Carro
{
//cualquier cdigo aqu
}

public class Toyota extends Carro
{
/*Toyota est heredando de carro, no olvidemos que Toyota
hereda los miembros de Carro incluido mtodos y variables*/
}


"Carro" tambin es un vehculo as que se podra implementar un rbol de herencia de la siguiente
manera:

public class Vehiculo{...}
public class Carro extends Vehiculo{...}
public class Toyota extends Carro{...}


En trminos de OO podramos decir lo siguiente:
Vehculo es la sper clase de Carro
Carro es la subclase de Vehculo
Carro es la sper clase de Toyota
Toyota es la subclase de Carro
Toyota hereda de Carro y de Vehiculo
Toyota deriva de Carro
Carro deriva de Vehculo
Toyota es subtipo de Carro y Vehiculo
Retornando a la relacin IS-A, lo siguiente es correcto:

Toyota extends Carro significa Toyota IS-A Carro

Carro extends Vehiculo significa Carro IS-A Vehiculo

Ahora recordemos que al principio usamos el operador instanceof, bueno, si la expresin
"Toyota instanceof Carro" es verdadera, entonces es lo mismo que decir "Toyota IS-A
Carro", la expresin "Toyota instanceof Vehiculo" tambin es verdadera aunque
explcitamente no dice esto ya que "Toyota" extiende de "Carro", pero por otro lado "Carro" si
extiende de "Vehiculo" a esto se le llama herencia indirecta ya que una clase puede ser hijo,
nieto, bisnieto, etc. de otra clase, una clase puede extender o heredar de otra directa o
indirectamente ya que en el rbol de herencia pueden haber clases intermedias.
HASA

La relacin HAS-A esta basada en el uso en lugar de la herencia, por ejemplo "A HAS-A B" si la
clase "A" tiene una referencia a una instancia de la clase "B", por ejemplo:

public class Animal{ }

public class Gato extends Animal
{
CajaDeArena miCajaDeArena;
}


En el cdigo anterior la clase "Gato" tiene una referencia una variable de instancia del tipo
"CajaDeArena", entonces podemos decir "Gato HAS-A CajaDeArena", en otra palabras,
"Gato" tiene una referencia a una "CajaDeArena", la clase "Gato" puede tener un mtodo
llamado "llenarCaja(Arena miArena)", de esta manera los usuarios de la clase "Gato" no
podrn saber nunca que cuando se invoca al mtodo "llenarCaja" este mtodo delega toda la
responsabilidad a la clase "CajaDeArena" llamando a su mtodo "llenarCaja", veamos esto
con un ejemplo:

public class Gato extends Animal
{
private CajaDeArena miCajaDeArena;

public void llenarCaja(Arena miArena)
{
miCajaDeArena.llenarCaja(miArena); /*delegando comportamiento al
objeto CajaDeArena */
}
}

public class CajaDeArena
{
public void llenarCaja(Arena miArena)
{
System.out.println("Llenando la caja de arena");
}
}


En OO muchas veces no queremos que la gente se preocupe por cual clase u objeto est
haciendo realmente el trabajo, los usuarios de la clase "Gato" hacen llamado del mtodo
"llenarCaja" pero estos no saben si la misma clase hace el trabajo o no, sin embargo a ellos les
parece que la propia clase "Gato" lo hace, no tienen ni idea de que existe algo como una clase
llamada "CajaDeArena" que es quien realmente hace el trabajo.

Toda la explicacin anterior nos servir para entender mejor otro de los conceptos de la
programacin orientada a objetos, uno de los ms tiles si sabemos cmo utilizarlo correctamente:
el polimorfismo.

Polimorfismo
Cualquier clase que pase la prueba de tener la relacin "IS-A" puede ser considerada polimrfica,
todos los objetos en Java son polimrficos ya que pasan la prueba de la relacin IS-A, tanto para
su propio tipo como para con la clase "Object". Debemos recordar la nica forma de a un objeto
es a travs de una variable de referencia, hay algunas cosas claves que debemos recordar de las
variables de referencia:
Una variable de referencia puede ser slo de un tipo y una vez declarado este tipo
nunca podr cambiar (aunque el objeto al que hace referencia puede cambiar).
Una referencia es una variable, por lo cual su valor puede ser reasignada a otros objetos a
menos que esta sea declarada como final.
Un tipo de variable de referencia determina los mtodos que se pueden invocar en el
objeto que esta variable est referenciando.
Una variable de referencia puede referirse a cualquier objeto del mismo tipo que el que
est declarando, o puede referirse a cualquier subtipo del tipo declarado.
Una variable de referencia puede ser declarado como un tipo de clase o un tipo de interfaz.
Si la variable se declara como un tipo de interfaz, se puede hacer referencia a cualquier objeto de
cualquier clase que implementa la interfaz.


Anteriormente creamos una clase "Animal" que era extendida por dos clases, "Perro" y "Gato",
ahora imaginemos que tenemos una clase llamada "Gaviota", despus queremos hacer que
algunos tipos de Animal vuelen o se puedan elevar en el aire y otros no como el caso de
"Gaviota" que si puede elevar, por el contrario "Perro" y "Gato" no pueden hacerlo, para esto
podramos crear una clase llamada "Elevable" con un mtodo "elevar" y hacer que unos tipos
de Animales puedan elevarse y otros no, pero tambin queremos que todos los tipos
de Animal se muevan que es lo que nos permite el mtodo "muevete" de la clase "Animal", pero
esto no funcionara ya que Java solo soporta la herencia simple, esto significa que una sub clase
slo puede tener una clase padre, es decir lo siguiente es incorrecto:

public class Gaviota extends Animal, Elevable // NO!!
{
//Cualquier codigo aqu
}


Una clase NO puede extender de ms que de slo una clase, ante estos casos la solucin sera
crearse una interface llamada "Elevable" y solo las sub-clases de "Animal" que puedan volar
implementen esta interfaz, dicha interfaz quedara de la siguiente manera:

public interface Elevable
{
public void volar();
}

public class Animal
{
public void muevete()
{
System.out.println("Me estoymoviendo");
}
}


A continuacin mostramos la clase "Gaviota" que implementa esta interfaz:

public class Gaviota extends Animal implements Elevable
{
public void volar()
{
System.out.println("Estoy volando!");
}
}


Ahora tenemos a la clase "Gaviota" que pasa la prueba de la relacin IS-A tanto para la clase
"Animal" como para la interfaz "Elevable", esto significa que una "Gaviota" puede ser tratada
polimrficamente como una de estas cuatro cosas en un momento dado, dependiendo del tipo
declarado de la variable de referencia:
Como un "Object" (ya que todas las clases heredan de la clase Object).
Como un "Animal" (ya que est extendiendo de la clase Animal).
Como una "Gaviota" (ya que es lo que es).
Como un "Elevable" (ya que implementa de la interface Elevable).


Las siguientes declaraciones son legales:

Gaviota gaviota = new Gaviota();
Object object = gaviota;
Animal animal = gaviota;
Elevable elevable = gaviota;


Aqu solo hay un objeto Gaviota pero cuatro diferentes variables de referencia, hagamos una
pregunta: Cul de las cuatro variables de referencia puede llamar al mtodo "muevete"?
Recuerden que las llamadas a mtodos permitidos por el compilador se basan nicamente en el
tipo declarado de la referencia, con independencia del tipo de objeto. As que buscando en los
cuatro tipos de referencia de nuevo, "Object", "Gaviota", "Animal" y "Elevable" cul de
estos cuatro tipos puede llamar al mtodo "muevete()"? La respuesta es la siguiente: El objeto
"animal" como el objeto "gaviota" son conocidos por el compilador para poder llamar o invocar
al mtodo "muevete".

Qu mtodos pueden ser invocados cuando el objeto "gaviota" est utilizando la referencia a la
inteface "Elevable"? Slo al mtodo "volar()".

Un beneficio es que cualquier clase desde cualquier lugar en el rbol de herencia puede invocar a
la interface "Elevable", que sucedera si tenemos un mtodo que tiene como argumento
declarado con tipo "Elevable", podras pasar una instancia de objeto del tipo "gaviota" y
cualquier otra instancia de clase que implemente a la interface "Elevable", podra usar el
parmetro del tipo "Elevable" para invocar al mtodo "volar()" pero no al mtodo
"muevete()" o cualquier otro objeto que se sabe que el compilador conocer basado en el tipo de
referencia.

Otra cosa que debemos saber es que si bien el compilador solo conoce al tipo de referencia
declarado, la JVM en tiempo de ejecucin sabe lo que el objeto realmente es, y eso significa que
incluso si el objeto "gaviota" hace una llamada al mtodo "muevete" usando la variable de
referencia "animal", si el objeto "gaviota" sobre-escribe el mtodo "muevete", la JVM invocara a
esa versin del mtodo "muevete". La JVM mira al objeto real que se encuentra al otro extremo de
la referencia, puede ver que se ha sobre escrito el mtodo del tipo de variable de referencia
declarado e invoca al mtodo del objeto de la clase actual.

Siempre se puede hacer referencia a un objeto con un tipo de referencia variable ms general (una
superclase o interfaz), pero en tiempo de ejecucin, las nicas cosas que son seleccionadas
dinmicamente basndose en el objeto real (en lugar de tipo de referencia) son mtodos de
instancia (no los mtodos estticos, no las variables), slo los mtodos de instancia sobre-escritos
se invocan de forma dinmica en funcin del tipo de objeto real.

Ejemplo:

public class Animal
{
public void muevete()
{
System.out.println("Me estoy moviendo");
}

public static void respirar() //Mtodo esttico
{
System.out.println("Estoy respirando");
}
}

public class Gaviota extends Animal
{
public void muevete()
{
System.out.println("La gaviota se mueve");
}

public static void respirar() //Mtodo esttico
{
System.out.println("La gaviota est respirando");
}
}

public class Prueba
{
public static void main(String... args)
{
Animal a = new Gaviota();
a.muevete();
a.respirar();
}
}


Salida:

La gaviota se mueve
Estoy respirando


El segundo resultado que vemos se trata de la invocacin de un mtodo esttico. El
comportamiento que vemos pasa porque cuando el compilador ve que se est invocando un
mtodo esttico, cambia la referencia al objeto por el tipo de la clase, o sea que al final queda de la
siguiente manera:

Animal a = new Gaviota();
Animal.respirar();


En el primer caso el mtodo que se invoca es el de "Gaviota" y no el de "Animal", ya que el
mtodo "muevete" no es esttico sino un mtodo de instancia; por eso dice se dice que slo los
mtodos de instancia sobrecargados se invocan de forma dinmica en funcin del tipo de objeto
real.

Sobrecarga y sobre escritura

Sobre escritura de mtodos
En cualquier momento que se tenga un mtodo que hereda de una superclase, se tendr la
oportunidad de realizar una sobre-escritura de mtodos, a menos que el mtodo este marcado con
la palabra reservada final. El principal beneficio de la sobre-escritura de mtodos es que se
puede definir un comportamiento especial para un mtodo de una subclase. En el siguiente
ejemplo veremos cmo la clase "Gaviota" sobre-escribe el mtodo "muevete" de la clase
"Animal":

public class Animal
{
public void muevete()
{
System.out.println("Me estoy moviendo");
}
}

public class Gaviota extends Animal
{
public void muevete()
{
System.out.println("La gaviota se mueve");
}
}


Para mtodos abstractos que se heredan desde una superclase, no se tiene otra opcin ms que
sobre escribir-dichos mtodos. Se deben implementar los mtodos a menos que la subclase que
los herede tambin este marcada como abstracta. Los mtodos abstractos deben ser
implementados por una subclase concreta, esto quiere decir que la subclase concreta sobre-
escribe el mtodo abstracto de la superclase. Entonces debemos pensar que los mtodos
abstractos son mtodos que forzosamente deben ser sobre-escritos.

El creador de la clase "Animal" podra haber decidido que, a efectos de polimorfismo, todos los
subtipos de Animal deben implementar el mtodo "moverse", de una manera nica y especifica.
Polimrficamente, cuando alguien tiene una referencia de Animal que no refiere a una instancia
de Animal, sino a una instancia de una subclase de Animal, la persona que llama debe ser
capaz de invocar al mtodo "muevete" en la referencia a "Animal", pero el objeto en tiempo de
ejecucin real ejecutar su propio y especifico mtodo "muevete". Marcando el mtodo "muevete"
como abstracto es la forma que el programador de la clase "Animal" dice a todos los
desarrolladores de las dems subclases: "No tiene ningn sentido para el nuevo
subtipo utilizar el mtodo genrico "muevete", por lo que t debes
implementar tu propio mtodo "muevete". A continuacin mostraremos un ejemplo de
clases no abstractas:

public class Prueba
{
public static void main(String... args)
{
Animal a = new Animal();
Animal b = new Gaviota(); //Referencia a Animal, pero objeto
Gaviota
a.muevete();
b.muevete();
}
}

public class Animal
{
public void muevete()
{
System.out.println("Me estoy moviendo");
}
}


public class Gaviota extends Animal
{
public void muevete()
{
System.out.println("La gaviota se mueve");
}

public void volar()
{
System.out.println("La gaviota vuela");
}
}


En el cdigo anterior la clase "Prueba" utiliza una referencia a "Animal" para invocar un mtodo
en el objeto "Gaviota", hay que recordar que el compilador solo permitir que se invoquen
mtodos que se encuentran en la clase "Animal", cuando usas una referencia a un "Animal". Por
lo tanto, el siguiente cdigo no es legal:

Animal c = new Gaviota();
c.volar(); // No puedes invocar a "volar()", Animal no tiene un mtodo
volar


Para reiterar: el compilar solo mira el tipo de referencia y no el tipo de instancia en tiempo de
ejecucin. El polimorfismo nos permite tener referencias a sper tipos o a tipos ms abstractos
(incluyendo las interfaces) para referir a uno de estos subtipos (incluyendo implementacin de
interfaces).

El mtodo que sobre-escribe no debe tener un modificador de acceso ms restringido que el del
mtodo a ser sobre-escrito. Por ejemplo no se puede sobre-escribir un mtodo marcado con el
modificador de acceso public y cambiarlo a protected. Pensemos en los siguiente: si la clase
"Animal" tiene un mtodo "comer()" marcado "public" y alguien tiene una referencia de
"Animal", es decir, una referencia declarada del tipo "Animal", se asume que es seguro llamar al
mtodo "comer()" en la referencia de "Animal", independientemente de la instancia actual que la
referencia a "Animal" est invocando. Si una subclase cambia el modificador de acceso del
mtodo sobre-escrito, entonces cuando la JVM invoque la verdadera versin del objeto "Gaviota"
en lugar de la versin del tipo de referencia "Animal", el programa perecer, a continuacin un
ejemplo:

public class Prueba
{
public static void main(String... args)
{
Animal a = new Animal();
Animal b = new Gaviota(); // Referencia a Animal, pero objeto
Gaviota
a.muevete();
b.muevete();
}
}

public class Animal
{
public void muevete()
{
System.out.println("Me estoy moviendo");
}
}

public class Gaviota extends Animal
{
private void muevete() //Marcado como privado
{
System.out.println("La gaviota se mueve");
}
}


Si el cdigo anterior compilara (cosa que no har) obtendramos el siguiente error en tiempo de
ejecucin:

Animal b = new Gaviota(); //Referencia a Animal, pero objeto Gaviota
a.muevete(); //Ocurre una crisis en tiempo de ejecucin


La variable "b" es del tipo "Animal", el cual tiene un mtodo pblico llamado "muevete", pero hay
que recordar que en tiempo de ejecucin, Java utiliza la invocacin de mtodos virtuales para
seleccionar dinmicamente la versin real del mtodo que se ejecutar, basado en la del tipo del
objeto en tiempo de ejecucin. Una referencia de "Animal" puede referir siempre a una instancia
de "Gaviota" porque "Gaviota" IS-A "Animal" ("Gaviota" ES UN "Animal"). Lo que hace
posible que una instancia de una superclase referencie a una instancia de la subclase es que la
subclase es capaz de hacer todo lo que la superclase puede hacer (ya que recibe el
comportamiento de esta por herencia). Esto quiere decir que cualquiera con una referencia a
"Gaviota" usando una instancia deAnimal (Animal a = new Gaviota();) es libre de llamar
a todos los mtodos accesibles de "Animal", no importa si "Gaviota" sobre-escribe los mtodos
de "Animal" o simplemente los hereda. Un mtodo-sobre escrito debe cumplir con el contrato de
la superclase.

Las reglas para sobre escribir un mtodo son las siguientes:
La lista de argumentos debe ser exactamente igual (del mismo tipo y en el mismo orden)
que el mtodo a sobre-escribir. Si esta lista no coincide en realidad lo que se est haciendo es una
sobrecarga del mtodo (que puede que no sea nuestra intencin).
El tipo de retorno del mtodo sobre escrito debe ser el mismo o un subtipo del declarado
en el mtodo de la sper clase.
El modificador de acceso no debe ser ms restrictivo que del mtodo a sobre-escribir. Por
ejemplo, si en la clase base tenemos un mtodo "public" NO podemos sobre-escribirlo
ponindole un modificador "protected".
El modificador de acceso puede ser menos restrictivo que el del mtodo a sobre-escribir.
Por ejemplo, si en la clase base tenemos un mtodo "protected" SI podemos sobre-escribirlo
ponindole un modificador "public".
Los mtodos de instancia solo pueden ser sobre-escritos si estos son heredados por la
subclase. Una subclase dentro del mismo paquete que su superclase puede sobre escribir
cualquier mtodo de la sper clase que NO est marcado comoprivate o final. Una subclase
en diferente paquete puede sobre-escribir solo los mtodos no finales
marcados public oprotected (los mtodos protected son heredados por la subclase).
Los mtodos sobre-escritos no deben lanzar excepciones marcadas (en las que sean
necesarias un try catch) que sean nuevas o ms amplias que aquellas declaradas en el mtodo
que sobre-escribe. Por ejemplo un mtodo que declara un "FileNotFoundException" no puede
ser sobre-escrito por un mtodo que declara un "SQLException", "Exception", "IOException"
o cualquier otra excepcin a menos que esta sea una subclase de "FileNotFoundException".
Los mtodos sobre-escritos pueden lanzar excepciones ms especficas (excepciones que
extiendan de la excepcin que se est declarando) o lanzar menos excepciones. Solo porque el
mtodo a sobre-escribir puede lanzar excepciones no quiere decir que el mtodo sobre-escrito
lanzara estas mismas excepciones, un mtodo sobre-escrito no tiene que declarar una excepcin
que nunca lanzar. Independientemente de que el mtodo a sobre-escribir las declare.
No se puede sobre-escribir un mtodo marcado con final.
No se puede sobre-escribir un mtodo marcado con static.
Si un mtodo no puede ser heredado entonces no puede ser sobre-escrito. Hay que
recordar que la sobre-escritura implica que se est re-implementando un mtodo que est
heredanddo. Por ejemplo el siguiente cdigo no es legal:

public class Prueba
{
public static void main(String... args)
{
Gaviota a = new Gaviota();
a.muevete(); //No es legal porque Gaviota no hereda muevete(),
muevete() es declarado private en Animal
}
}

public class Animal
{
private void muevete()
{
System.out.println("Me estoy moviendo");
}
}

public class Gaviota extends Animal {}


Invocando a la versin de la superclase de un mtodo sobre escrito
Tal vez queramos tomar ventaja de una parte del cdigo en la versin de la sper clase de un
mtodo y aun as sobre-escribirlo para proveer algn comportamiento especifico adicional. Esto es
como decir: "Ejecuta la versin de la superclase de un mtodo, despus vuelve y termina con mi
cdigo para hacer un comportamiento adicional en el mtodo de la subclase", esto es fcil de hacer
utilizando la palabra reservada super como en el ejemplo siguiente:

public class Prueba
{
public static void main(String... args)
{
Gaviota a = new Gaviota();
a.muevete();
}
}

public class Animal
{
public void muevete()
{
System.out.println("Me estoy moviendo");
}
}

public class Gaviota extends Animal
{
public void muevete()
{
//podemos agregar alguna cosa mas
super.muevete(); //invoca al cdigo de la superclase (Animal)
}
}


Usar la palabra reservada "super" para invocar a un mtodo sobre-escrito slo se aplica para
mtodos de instancia, hay que recordar quelos mtodos marcados con static no pueden ser
sobre escritos.

Sobrecarga de mtodos
La sobrecarga de mtodos permite usar el mismo nombre de un mtodo en una clase, pero con
diferentes argumentos y, opcionalmente, un tipo de retorno diferente, el cdigo asume la carga de
hacer frente a diferentes tipos de argumentos en lugar de obligar a la persona que llama a hacer
las conversiones antes de invocar el mtodo. Las reglas a seguir para la sobrecarga son simples:
Para sobrecargar mtodos se debe cambiar la lista de argumentos.
Para sobrecargar mtodos se puede cambiar el tipo de datos de retorno.
Para sobrecargar mtodos se puede cambiar el modificador de acceso.
Para sobrecargar mtodos se pueden declarar excepciones que sean nuevas o ms
amplias.
El mtodo puede ser sobrecargado en la misma clase o en una subclase.
Si la clase "A" define un mtodo "hacerAlgo(int i)", la subclase "B" puede definir un
mtodo llamado "hacerAlgo(String s)", sin sobre-escribir el mtodo "hacerAlgo(int i)"
de la sper clase que toma como argumento un entero. Dos mtodos con el mismo nombre pero
en diferentes clases pueden ser consideradas sobrecargados, si la sub-clase hereda una versin
del mtodo y luego declara otra versin sobrecargada en la definicin de la clase.


Formas legales de sobrecargar un mtodo
El mtodo que queremos sobrecargar es el siguiente:

public void unMetodo(String str, int t, double d){}


Los siguientes mtodos son legales para sobrecargar el mtodo anterior:

public void unMetodo(String str, int t){}

public int unMetodo(String str, double d){}

public void unMetodo(String str, int t)throws IOException{}


Invocando a mtodos sobrecargados
Cuando un mtodo es invocado, ms de un mtodo con el mismo nombre puede existir para el tipo
de objeto que estamos invocando. Por ejemplo la clase "Gaviota" puede tener tres mtodos con
el mismo nombre pero con diferente lista de argumentos, estos sern mtodos sobrecargados.
Definir cul de los diferentes mtodos se desea invocar depender de la lista de argumentos que
contenga. Si estamos invocando a un mtodo que tiene un "String" como argumento, el mtodo
que tiene un "String" como argumento ser llamado. A continuacin veremos un ejemplo:

public class UnaClase
{
public int unMetodo(int x, int y)
{
return x + y;
}

public double unMetodo(double x, double y)
{
return x + y;
}
}

public class Prueba
{
public static void main(String... args)
{
UnaClase a = new UnaClase();
int x = 9;
int y = 5;

int resultado = a.unMetodo(x, y); //Qu versin de "unMetodo"
es invocado?

double otroResultado = a.unMetodo(5.2, 3.6); //Qu versin es
invocada?
}
}


En el primer caso se llama a la primera versin del mtodo "unMetodo(x,y)" ya que se est
pasando a dos enteros y en el segundo caso se llama a la versin del mtodo "unMetodo" que
recibe dos argumentos del tipo double.

La invocacin de mtodos sobrecargados que reciben objetos en lugar de tipos primitivos es un
poco ms interesante. Si tenemos un mtodo sobrecargado, que en un mtodo toma un objeto del
tipo "Animal" y otro en el que toma un objeto del tipo "Gaviota" (subclase de "Animal"). Si
pasamos un objeto del tipo Gaviota cuando invocamos al mtodo, invocaremos a la versin
sobrecargada que toma una "Gaviota". O al menos eso parece a primera vista:

class Animal{}

class Gaviota extends Animal{}

public class UsaAnimales
{
public void muevete(Animal a)
{
System.out.println("Estas en la versin de Animal");
}

public void muevete(Gaviota g)
{
System.out.println("Estas en la versin de Gaviota");
}

public static void main(String... args)
{
UsaAnimales ua = new UsaAnimales();
Animal a = new Animal();
Gaviora g = new Gaviota():
ua.muevete(a);
ua.muevete(g);
}
}


La salida es la que esperamos:

Estas en la versin de Animal
Estas en la versin de Gaviota


Pero qu sucede si usamos una referencia de "Animal" para un objeto "Gaviota"?

Animal animalReferenciaGaviota = new Gaviota();
ua.muevete(animalReferenciaGaviota);


Cul de las versiones del mtodo "muvete" es invocada?, podramos pensar que la respuesta
es: "El que toma una "Gaviota", ya que es un objeto del tipo "Gaviota" el que en tiempo de
ejecucin est siendo pasado al mtodo". Pero no es as como funciona. El cdigo anterior imprime
lo siguiente:

Estas en la versin de Animal


El objeto en tiempo de ejecucin es una "Gaviota" y no un "Animal". La eleccin de cul mtodo
sobrecargado se deber llamar no es decidido dinmicamente en tiempo de ejecucin. Slo
hay que recordar que el tipo de referencia, no el tipo de objeto, determina qu mtodo
sobrecargado es llamado.

Para resumir lo que hemos visto hasta ahora de sobrecarga y sobre-escritura: cul versin de un
mtodo sobre-escrito es llamado (en otras palabas, desde cul clase en el rbol de herencia) es
decidido en tiempo de ejecucin por el tipo de objeto; pero cul versin del mtodo sobrecargado
se llamar est basado en el tipo de referencia del argumento que se pasa en tiempo de
compilacin. Si invocamos un mtodo pasando una referencia de "Animal" para un objeto
"Gaviota", el compilador solo sabe que est recibiendo un "Animal", por lo que elige la versin
sobrecargada que toma un "Animal". No importa que en tiempo de ejecucin realmente se pase
una "Gaviota".

Polimorfismo en mtodos sobrecargados y sobre-escritos
Cmo trabaja el polimorfismo en mtodos sobrecargados? Si pasamos una referencia de
"Animal", el mtodo que toma un "Animal" ser llamado, incluso si el objeto actual pasado es
una "Gaviota". Una vez que la "Gaviota" disfrazada de "Animal" entra en el mtodo, sin
embargo, el objeto "Gaviota" sigue siendo una "Gaviota" a pesar de ser pasado a un mtodo
que recibe un "Animal". Entonces es verdad que el polimorfismo no determina que versin del
mtodo sobrecargado ser llamado. El polimorfismo entra en juego cuando se decide cul versin
de un mtodo sobre-escrito es llamado. Pero algunas veces un mtodo puede ser ambos, sobre-
escrito y sobrecargado. Imaginemos lo siguiente:

public class Animal
{
public void comer()
{
System.out.println("El Animal genrico est comiendo");
}
}

public class Gaviota extends Animal
{
public void comer()
{
System.out.println("La gaviota est comiendo");
}

public void comer(String s)
{
System.out.println("La gaviota est comiendo esto: " + s);
}
}


Noten que la clase "Gaviota" tiene sobrecargado y sobre-escrito el mtodo "comer" (el mtodo
sobrecargado es el que recibe unString y el sobre-escrito el que no recibe nada).

La siguiente tabla muestra cul de las versiones del mtodo "comer" ser llamado dependiendo de
cmo sea invocado:
Cdigo de Invocacin al
mtodo
Resultado
Animal a = new
Animal();
a.comer();
"el Animal genrico est comiendo"
Gaviota g = new
Gaviota();
g.comer();
"La gaviota est comiendo"
Cdigo de Invocacin al
mtodo
Resultado
Animal ag = new
Gaviota();
ag.comer();
"La gaviota est comiendo"
Polimorfismo trabajando: El objeto actual
("Gaviota"), no el tipo de referencia ("Animal"), es
usado para determinar cul versin del mtodo
"comer" es llamado.
Gaviota gp = new
Gaviota();
gp.comer("peces")
"La gaviota est comiendo esto:
peces"
El mtodo sobre cargado "comer(String s)" es
llamado.
Animal a2 = new
Animal();
a2.comer("manzanas");
Error de compilacin!!
El compilador mira la clase Animal y ve que no tiene
un mtodo comer que reciba un String.
Animal ag2 = new
Gaviota();
ag2.comer("peras");
Error de compilacin!!
El compilador ve solo la referencia y sabe que
"Animal" no tiene un mtodo "comer" que reciba
unString. Al compilador no le importa que el objeto
actual pueda ser una "Gaviota" en tiempo de
ejecucin.


Diferencias entre mtodos sobre cargados y sobre escritos:

Mtodo sobrecargado Mtodo sobre-escrito
Argumento(s) Debe cambiar. No debe cambiar.
Tipo de
retorno
Puede cambiar.
No puede cambiar, excepto para
retornos covariantes.
Excepciones Puede cambiar.
Pueden no declarar una excepcin del
mtodo que sobre-escribe, o declarar
una subclase de esta excepcin. No debe
lanzar nuevas excepciones o ms
"amplias" que aquellas declaradas en el
mtodo que sobre-escribe.
Nivel de
Acceso
Puede cambiar.
No pueden tener un nivel de acceso ms
restrictivo, pero si uno igual o menos
restrictivo.

Mtodo sobrecargado Mtodo sobre-escrito
Invocacin
El tipo de referencia
determina cul mtodo
sobrecargado es
seleccionado, basado en el
tipo de argumentos
declarados. Sucede en
tiempo de compilacin.
El mtodo real que se invoca es todava
una invocacin de mtodo virtual que
siempre sucede en tiempo de ejecucin,
pero el compilador ya sabe la firma del
mtodo que se invoca. El tipo de objeto
determina cul mtodo es
seleccionado. Sucede en tiempo de
ejecucin.


Casting de variables de referencia
Hasta el momento hemos visto como es posible y comn el uso de variables de referencia
genricas para referirse a tipos de objetos ms especficos, eso es el corazn del polimorfismo,
como ejemplo veamos la siguiente lnea de cdigo:

Animal animal = new Gaviota();


Pero qu sucede si queremos usar una variable de referencia "Animal" para invocar un mtodo
que solo la clase "Perro" tiene? Sabemos que nos estamos refiriendo a un Perro y queremos
hacer una cosa especfica de Perro.

En la siguiente lnea de cdigo tendremos un arreglo de Animales y cada vez que encontremos
una Perro en el arreglo, haremos algo especial de Perro. Asumamos por el momento que todo el
cdigo escrito a continuacin est correcto, solo que no estamos seguros de la lnea de cdigo que
invocara al mtodo "hacerRuido".

public class Animal
{
void hacerRuido()
{
System.out.println("Ruido Generico");
}
}

public class Perro extends Animal
{
void hacerRuido()
{
System.out.println("Ladrando");
}

void hacerseElMuerto()
{
System.out.println("Muriendo");
}
}

public class Prueba
{
public static void main(String... args)
{
Animal[] a = {new Animal(), new Perro(), new Animal()};

for(Animal animal: a)
{
animal.hacerRuido();

if(animal instanceof Perro)
{
animal.hacerseElMuerto(); //Se intenta invocar un metodo
de Perro?
}
}
}
}


Cuando compilemos el cdigo anterior, el compilador nos enviara un mensaje como:

Cannot find Symbol


El compilador nos est diciendo: "Oye, la clase "Animal" no tiene un mtodo
"hacerseElMuerto"".

Ahora modifiquemos el bloque de la condicional if:

if(animal instanceof Perro)
{
Perro perro = (Perro) animal; // Casteando la variable de referencia
perro.hacerseElMuerto();
}


El nuevo y mejorado bloque de cdigo contiene un "cast", el cual en algunos casos es
llamado down casting, porque estamos bajando en el rbol de herencia a una categora mas
especifica.

Ahora el compilador no nos dar problemas, casteamos la variable "animal" a un tipo "Perro". El
compilador nos est diciendo lo siguiente: "Sabemos que nos estamos refiriendo a un objeto del
tipo Perro, est bien hacer una nueva variable de referencia de tipoPerro, para referirnos a este
objeto", en este caso estamos bien, porque antes de intentar el "cast" hicimos una prueba
deinstanceof para asegurarnos.

Es importante saber que el compilador confa en nosotros cuando hacemos un down
casting aun cuando pudiramos hacer algo como lo siguiente:

public class Animal{}

public class Perro extends Animal{}

public class Prueba
{
public static void main(String... args)
{
Animal animal = new Animal();
Perro perro = (Perro)animal; //Compila pero fallara despus
}
}


Este cdigo compilara correctamente pero cuando intentemos ejecutarlo vamos a obtener una
excepcin como la siguiente:

java.lang.ClassCastException


Por qu no podemos confiar en el compilador para que nos ayude en esto? No puede ver
que animal es del tipo "Animal"? Todo lo que el compilador puede hacer es comprobar que los
dos tipos pertenezcan al mismo rbol de herencia, por lo que dependiendo de lo que el cdigo
puede hacer antes del down casting, es posible de que "animal" sea del tipo "Perro". El
compilador puede permitir cosas que posiblemente puedan funcionar en tiempo de ejecucin. Sin
embargo si el compilador sabe con certeza que el cast no puede funcionar, entonces la
compilacin fallara. El siguiente bloque de cdigo NO compilar:

Animal animal = new Animal();
Perro p = (Perro) animal;
String s = (String) animal; //animal nunca puede ser un String


En este caso obtendremos un error como el siguiente:

inconvertible types


A diferencia del down-casting, el up-casting (convertir a un tipo ms general en el rbol de
herencia) trabaja implcitamente porque cuando estmos haciendo up-casting estamos
implcitamente restringiendo el numero de mtodos que podemos invocar, lo que impide que ms
adelante podamos invocar a un mtodo ms especifico, por ejemplo:

class Animal{}

class Perro extends Animal{}

class Prueba
{
public static void main(String args)
{
Perro p = new Perro();
Animal a1 = p; //upCasting, se puede sin conversin explicita
Animal a2 = (Animal)p; // upCasting, se puede con conversin
explicita
}
}


Ambos up-castings anteriores compilaran y se ejecutaran sin excepcin, porque un "Perro"
ES-UN "Animal", lo que significa que lo que cualquier "Animal" pueda hacer, el "Perro" lo har.
Un "Perro" puede hacer ms, pero en este punto, cualquiera con una referencia de "Animal"
puede llamar con seguridad a los mtodos de "Animal" en una instancia de "Perro". Los mtodos
de "Animal" pueden haber sido sobre-escritos en la clase "Perro", pero todo lo que importa ahora
es saber que un "Perro" puede hacer todo lo que un "Animal" puede hacer. El compilador y
la JVM saben esto tambin, entonces el up-casting implcito es siempre legar para la asignacin
de un objeto de un subtipo para una referencia a su sper tipo o interface. Si "Perro" implementa
la interface "Mascota", y "Mascota" define el mtodo "seAmigable()", un "Perro" puede
implcitamente hacer casting a una "Mascota", pero el nico mtodo de "Perro" que se podr
invocar es "seAmigable()", el cual "Perro" fue forzado a implementar porque "Perro"
implement a la interface "Mascota".

Una cosa ms, si "Perro" implementa a la interface "Mascota", y si "Sabueso" extiende a
"Perro", pero "Sabueso" no declara que este implementando a "Mascota", "Sabueso" sigue
siendo una "Mascota", "Sabueso" es una "Mascota" simplemente porque este est extendiendo
a "Perro". La clase "Sabueso" puede siempre sobre-escribir cualquier mtodo que este
heredando desde "Perro", incluyendo los mtodos que "Perro" implementa para cumplir con el
contrato de la interfaz.

Por ltimo, si "Sabueso" declara que implementa a "Mascota", es solamente para que los que
busquen en "Sabueso" puedan ver fcilmente que "Sabueso" ES-UNA "Mascota", sin tener que
mirar a la superclase de "Sabueso". "Sabueso" no tiene la necesidad de implementar el mtodo
"seAmigable()" si la clase "Perro" (sper clase de "Sabueso") ya se ha ocupado de eso. En
otras palabras, si "Sabueso" ES-UN "Perro", y "Perro" ES-UNA "Mascota", entonces
"Sabueso" ES-UNA "Mascota", y ya ha cumplido con los mtodos de "Mascota" para la
aplicacin del mtodo "seAmigable()", ya que hereda el mtodo "seAmigable()". El
compilador es suficientemente inteligente para decir: "S que Sabueso es un Perro, pero est
bien para que sea ms obvio".

As que no hay que dejarse engaar por el cdigo que muestra una clase concreta que declara que
implementa una interfaz, pero no implementa el mtodo de la interface, antes de poder decir si el
cdigo es legal, debemos mirar cul es la superclase de la clase que esta implementado esta
interface. Si alguna clase en el rbol de herencia ya ha implementado mtodos concretos y ha
declarado que ella (la superclase) implementa la interfaz, entonces la subclase no tiene ninguna
obligacin de volver a implementar (sobre-escribir) los mtodos.

Implementando una interface
Cuando implementamos una interface estamos aceptando el contrato definido por la interfaz. Eso
quiere decir que estamos obligados a implementar todos los mtodos definidos por la interfaz y que
cualquiera que conozca los mtodos de la interfaz (no como lo implementa pero si como se llaman
y que retornan) puede invocar estos mtodos en una clase que implementa la interfaz.

Por ejemplo si creamos una clase que implemente a la interfaz "Runnable" (para que el cdigo
pueda ejecutarse en otro un hilo), debemos implementar el mtodo "public void run()", de lo
contrario el hilo ver que no tenemos implementado el mtodo "run" de la interface "Runnable" y
provocar un error. Afortunadamente, Java impide que esta crisis se produzca mediante la
ejecucin de un proceso de comprobacin, en el compilador, de cualquier clase que pretende
implementar una interfaz.

Si la clase est implementando una interface, deberamos tener una implementacin para cada
mtodo de la interface, con unas pocas excepciones que veremos en un momento.

Por ejemplo, imaginemos que tenemos la interfaz "Rebotable", con dos mtodos "rebotar()" y
"setFactorRebote", la siguiente clase compilar:

public class Pelota implements Rebotable //palabra reservada implements
{
public void rebotar(){}
public void setFactorRebote(int fr){}
}


El contrato garantiza que una clase tenga todos los mtodos de una interface pero no garantiza
que tenga una buena o correcta implementacin en el cuerpo del mtodo. El compilador nunca se
fijar que haya algo entre las llaves del mtodo, nunca dir que es un mtodo y que debera hacer
algo, solo se fija en que tenga los mtodos que se describen en la interface, nada ms.

Las clases que implementan una interface deben de seguir las mismas reglas para una clase que
extiende a una clase abstracta.

Las reglas para que una clase NO abstracta implemente correctamente una interface son las
siguientes:
Proveer implementacin para todos los mtodos declarados en la interface.
Seguir todas las reglas para una sobre-escritura legal (overrides).
No declarar excepciones, en la implementacin del mtodo, que no estn en el mtodo
definido en la interface. Se pueden declarar subclases de las declaradas por el mtodo de la
interfaz.
Mantener el mismo nombre del mtodo de la interface y el mismo tipo de dato de retorno (o
un subtipo).


Una clase que implementa una interface puede ser abstracta. Por ejemplo:

abstract class Pelota implements Rebotable{}


Notan que algo falta?, pues no estamos implementando los mtodos de la interfaz "Rebotable",
y no tenemos ningn error. Si la clase que implementa una interface es una clase abstracta esta
puede simplemente pasar la implementacin de los mtodos a la primera clase concreta que se
implemente.

Por ejemplo si tenemos la clase "PelotaPlaya" y esta extiende de la clase "Pelota", entonces la
clase "PelotaPlaya" debe de implementar todos los mtodos de la interfaz "Rebotable":

public class PelotaPlaya extends Pelota
{
/*A pesar que no se dice en la declaracin anterior (no hay
implements a Rebotable)
PelotaPlaya tiene que implementar a la interface Rebotable ya que
la super clase
abstracta de PelotaPlaya (Pelota) implementa a Rebotable */

public void rebotar(){}

public void setFactorRebote(int fr){}

/*Si la clase Pelota hubiera declarado algun mtodo abstracto,
entonces
ese mtodo debera estar implementado aqu tambin*/
}


A menos que la implementacin sea de una clase abstracta, la implementacin debe tener todos
los mtodos definidos por la interface.

Hay dos reglas ms que debemos saber:
1. Una clase puede implementar ms de una interface, por ejemplo:

public class Pelota implements Rebotable, Runnable, Serializable{}
Podemos extender solo a una clase, pero implementar a muchas interfaces. Pero recuerden que la
sub-clasificacin (extends) define quin y qu es nuestra clase, mientras que la implementacin
(implements) define una funcin que puede desempear o un sombrero que nuestra clase puede
usar, a pesar de lo diferente que podra ser de la otra clase que implemente la misma interface
(pero de un rbol de herencia diferente). Por ejemplo: "Persona extends SerHumano", pero
una "Persona" tambin puede ser (implements) "Programador", "Empleado", "Pariente".
2. Una interface puede tambin extender a otra interface, pero nunca implementar nada,
por ejemplo:

public interface Rebotable extends Movible{}
Qu significa esto? La primera clase concreta que implemente "Rebotable" debe implementar
todos los mtodos de esta interface, pero tambin debe implementar todos los mtodos de la
interface "Movible". La sub-interface simplemente est agregando ms requerimientos al contrato
de la super-interface.

Una interface puede extender a ms de una interface, pero sabemos que cuando hablamos de
clases esto es ilegal, por ejemplo:

public class Programador extends Empleado, Geek{} //Esto es ilegal!!


Como mencionamos anteriormente una clase no permite extender a ms de una clase en Java,
una interface, sin embargo, puede implementar a ms de una interface, por ejemplo:

public interface Rebotable extends Movible, Inflable //OK
{
void rebotar();
void setFactorRebote(int fr);
}

interface Movible
{
void muevete();
}

interface Inflable
{
void inflate();
}


En el prximo ejemplo, "Pelota" requiere implementar la interface "Rebotable", pero tambin
debe implementar todos los mtodos de las interfaces que "Rebotable" ha extendido, incluyendo
cualquier interface que aquellas interfaces extienden, y as sucesivamente hasta llegar a la parte
superior de la pila. "Pelota" debe tener lo siguiente:

public class Pelota implements Rebotable
{
public void rebotar(){} //implementando metodos de la
public void setFactorRebote(int fr){} //interface Rebotable

public void muevete(){} //implementando de Movible

public void inflate(){} //implementando de Inflable
}


Si la clase "Pelota" no implementa cualquiera de los mtodos de "Rebotable", "Movible" o
"Inflable", el compilador encontrar errores, al menos que "Pelota" sea una clase abstracta.
En el caso de que "Pelota" sea una clase abstracta esta puede implementar todos, algunos o
ningn mtodo de las interfaces, puede dejar la implementacin a una sub clase concreta de
"Pelota", por ejemplo:

abstract class Pelota implements Rebotable
{
public void rebotar(){} //define comportamiento de la
public void setFactorRebote(int fr){} //interface Rebotable

/*no implementa el resto de los mtodos, deja el resto para una sub-
clase concreta*/
}

class PelotaFutbol extends Pelota
{
/*implementando mtodos que pelota no hizo*/
public void muevete(){} //implementando de Movible

public void inflate(){} //implementando de Inflable

/*PelotaFutbol puede elegir sobre escribir el mtodo rebotar
implementado en pelota*/
public void rebotar(){}
}


Comparando ejemplos de abstracto y concreto de extender e implementar:



Ya que "PelotaFutbol" es la primera clase concreta que Implementa "Rebotable", esta debe
implementar todos los mtodos de la interface "Rebotable", excepto aquellos definidos en la
clase abstracta "Pelota". Ya que "Pelota" no provee implementacin de los mtodos de la
interface "Rebotable", es necesario que "PelotaFutbol" implemente todos aquellos mtodos.

Tipos Correctos de Retorno
El objetivo de esta seccin es cubrir dos aspectos de los tipos de retorno:
1. Qu se puede declarar como un tipo de retorno, y
2. Qu se puede retornar como un valor.
Qu se puede y no se puede declarar es muy sencillo, pero esto depende si estamos sobre-
escribiendo un mtodo, heredado o simplemente declarando un mtodo nuevo (el cual incluye
sobrecarga de mtodos). Daremos solo una pequea mirada a las diferencias entre las reglas para
los tipos de retorno para mtodos sobre cargados y sobre-escritos (overloaded y overriding).
Declaracin de tipos de retorno
Veremos qu est permitido para declarar como un tipo de retorno, lo cual depende primero en que
si estamos sobre-escribiendo, sobrecargando o declarando un nuevo mtodo.
Tipos de retorno en mtodos sobre cargados
Recuerden que un mtodo sobrecargado no es ms que una forma para la reutilizacin del mismo
nombre de un mtodo pero con diferentes argumentos. Un mtodo sobrecargado es un mtodo
completamente diferente de cualquier otro mtodo con el mismo nombre. Si heredamos un mtodo
pero lo sobrecargamos este en una subclase, este no est sujeto a las restricciones de sobre-
escritura, lo cual implica que podemos declarar cualquier tipo de retorno. Lo que no podemos hacer
es cambiar solo el tipo de retorno. Para sobre cargar un mtodo solo debemos cambiar la lista de
argumentos, por ejemplo:

public class Animal
{
void muevete(){};
}

public class Perro extends Animal
{
String muevete(int numeroPasos)
{
return null;
}
}


Noten que el mtodo de "Animal" tiene un tipo de retorno diferente que el mtodo de "Perro".
Esto est bien. En el momento que se ha cambiado la lista de argumentos, hemos sobrecargado el
mtodo, entonces el tipo de retorno no tiene que coincidir con el del mtodo de la sper clase, pero
por ejemplo, lo siguiente no est permitido:

public class Animal
{
void muevete(){};
}

public class Perro extends Animal
{
String muevete() //Error, no se puede cambiar solo el tipo de
retorno
{
return null;
}
}

Sobre escritura y tipos de retorno, retornos covariantes
Cuando una clase quiere cambiar la implementacin del mtodo de un mtodo heredado (sobre-
escrito), la subclase debe definir un mtodo que debe coincidir exactamente con el mtodo
heredado. O, a partir de Java 5, se le permite cambiar el tipo de retorno en el mtodo sobre-
escrito siempre y cuando el nuevo tipo de retorno es un subtipo del tipo de retorno declarado en el
mtodo a sobre-escribir (superclase).

class Alpha
{
Alpha hacerAlgo(char c)
{
return new Alpha();
}
}

class Beta extends Alpha
{
Beta hacerAlgo(char c) //sobre escritura legal en Java 1.5
{
return new Beta();
}
}


En Java 5 este cdigo compilara sin problemas, pero si intentamos compilar este cdigo
con Java 1.4, mostrar el siguiente error:

attempting to use incompatible return type


Otras reglas aplicadas a la sobre-escritura, incluyen aquellas para modificadores de acceso y
declaracin de excepciones.
Retornando un valor
Tenemos que recordar solo 6 reglas para retornar un valor:
1. Podemos retornar null a los mtodos que tengan como tipo de retorno un objeto,
ejemplo:

public Button hacerAlgo
{
return null;
}
2. Podemos declarar un arreglo como tipo de retorno sin problemas, ejemplo:

public String[] go()
{
return new String[] {"Alan", "Alex", "Diego", "y Peke", "Henry",
"Cesar", "Pedroww"};
}
3. En un mtodo con un tipo de retorno primitivo, podemos retornar cualquier valor o
variable que pueda ser implcitamente convertido al tipo de retorno declarado, ejemplo:

public int go()
{
char c = c;
return c; //char es compatible con int
}
4. En un mtodo con un tipo de retorno primitivo, podemos retornar cualquier valor o
variable que pueda ser explcitamente convertido al tipo de retorno declarado, ejemplo:

public int go()
{
float f = 32.5f;
return (int) f
}
5. No debemos retornar nada desde un mtodo que tiene como tipo de retorno "void",
ejemplo:

public void go()
{
return "Esto es todo"; //Error, no es legal
}
6. En un mtodo con un tipo de retorno con referencia a un objeto, podemos retornar
cualquier tipo de objeto que pueda ser implcitamente convertido al tipo de retorno declarado,
ejemplo:

public Animal getAnimal()
{
return new Perro(); //Asumiendo que Perro extiende de Animal
}

public Object getObject()
{
int[] nums = {1, 2, 3};
return nums; //retorna un arreglo de enteros, el cual sigue siendo
un //objeto
}

public interface Rebotable{}

public class Pelota implements Rebotable{}

public class TestPelota
{
//Mtodo con una interface como tipo de retorno
public Rebotable getRebotable()
{
return new Pelota(); //Retorna un implementador de la interface
}
}
Y con eso terminamos todo lo concerniente con las reglas para el retorno de tipos de valor. Ahora
veremos algunos detalles interesantes sobre constructores e instanciacin de objetos.
Constructores e Instanciacin
Los objetos son construidos. No podemos crear un nuevo objeto sin invocar a un constructor. No
podemos crear un nuevo objeto sin invocar al constructor del objeto actual y a los constructores de
sus superclases.

Los constructores son cdigo que se ejecuta cuando usamos la palabra reservada "new". Tambin
pueden ser bloques de inicializacin que se ejecutan al escribir "new" (son como constructores
pero un poco distintos), pero vamos a cubrir estos (bloques de inicializacin), y sus homlogos de
la inicializacin esttica, ms adelante. Vamos a ver cmo se codifican los constructores y como
trabajan en tiempo de ejecucin.
Constructores Bsicos
Todas las clases, incluyendo las clases abstractas, deben tener un constructor, pero solo porque
una clase deba de tener un constructor no quiere decir que necesitamos escribirlo explcitamente.
Un constructor es algo como esto:

public class Rectangulo
{
Rectangulo(){} //Constructor para la clase Rectangulo
}


Un constructor no retorna ningn tipo de valor. Hay dos cosas que siempre debemos recordar
acerca de los constructores:
1. 1. No retornan ningn tipo de valor y
2. 2. Llevan el mismo nombre que la clase.
Tpicamente los constructores son utilizados para inicializar el estado de las variables de instancia,
por ejemplo:

public class Rectangulo
{
private int ancho;
private int altura;

public Rectangulo (int ancho, int altura)
{
this.ancho = ancho;
this.altura = altura;
}
}


En el caso anterior, la clase "Rectangulo" no tienen un constructor sin argumentos, lo que
significa que el siguiente cdigo fallar en tiempo de compilacin:

Rectangulo r = new Rectangulo(); //No compila, no coinciden el
constructor


Pero el siguiente cdigo, compilar correctamente:

Rectangulo r = new Rectangulo(4,2); //No hay problema, los argumentos
coinciden con el constructor


Es muy comn (y deseable) tener un constructor sin argumentos, independientemente del nmero
de constructores sobrecargados que nuestra clase pueda tener (s, los constructores pueden ser
sobrecargados). De vez en cuando se tiene una clase en la que no tiene sentido crear una
instancia sin necesidad de suministrar informacin al constructor. Un "java.awt.Color", por
ejemplo, no puede ser llamado mediante una llamada a un constructor sin argumentos, porque es
como decirle a la JVM: "Hazme un nuevo color, y no me importa qu tipo de color sea este... tu
decide", realmente creen que la JVM pueda tomar decisiones de ese tipo?
Encadenamiento de constructores
Sabemos que los constructores son invocados en tiempo de ejecucin cuando usamos la palabra
reservada "new" de la siguiente manera:

Perro p = new Perro();


Pero qu es lo que realmente sucede cuando escribimos "new Rectangulo()"?

Asumamos que "Perro" extiende (hereda) de "Animal" y "Animal" extiende de "Object"
1. 1. El constructor de "Perro" es invocado. Cada constructor invoca al constructor
de su superclase con una llamada implcita a "super()", a menos que el constructor
invoque a un constructor sobrecargado de la misma clase, pero esto lo veremos ms
adelante.
2. 2. El constructor de "Animal" es invocado ("Animal" es la superclase de "Perro")
3. 3. El constructor de "Object" es invocado ("Object" es la ltima superclase de
todas las clases, entonces "Animal" extiende de "Object" a pesar de que no escribimos
explcitamente "extends Object" en la declaracin de la clase "Animal". Esto es
Implcito), en este punto estamos en el cima de la pila.
4. 4. Se asignan los valores explcitos a las variables de instancia. Nos referimos a
las variables que declaramos como "int x = 24", donde 24 es el valor explicito (en
comparacin con el valor por defecto) de la variable de instancia.
5. 5. El constructor de Object se completa.
6. 6. Se asignan los valores explcitos a las variables de instancia de "Animal" (si
tuviera).
7. 7. El constructor de "Animal" completa.
8. 8. Se asignan los valores explcitos a las variables de instancia de "Perro" (si
tuviera).
9. 9. El constructor de "Perro" completa.


A continuacin mostramos como trabajan los constructores en la pila de llamadas:
1. 4.- Object()
2. 3.- Animal() llamada a super()
3. 2.- Perro() llamada a super()
4. 1.- main() llamada a new Perro()

Reglas para los constructores:
A continuacin mostramos lo que debemos recordar acerca de los constructores:
Un constructor puede tener cualquier modificador de acceso, incluso "private" (un
constructor privado quiere decir que solo el cdigo dentro de la clase misma puede instanciar un
objeto de ese tipo, as que si la clase con constructor privado quiere permitir que una clase pueda
instanciarla, la clase debe proveer un mtodo esttico o variable que permitan acceder a una
instancia creada dentro de la clase).
El constructor debe tener el mismo nombre que la clase.
El constructor no debe retornar ningn tipo de valor.
Es legal (pero tonto) tener un mtodo con el mismo nombre de la clase, pero esto no hace
que sea un constructor. Si ven que tiene un tipo de retorno, entonces es un mtodo en vez de
un constructor. Podemos tener ambos, un mtodo y un constructor con el mismo nombre (el
nombre de la clase) en una misma clase y esto no es problema para Java.
Si no escribimos ningn constructor dentro de la clase, un constructor por defecto ser
automticamente generado por el compilador.
El constructor por defecto SIEMPRE es un constructor sin argumentos.
Si deseamos tener un constructor sin argumentos y ya hemos escrito algn otro
constructor dentro de la clase, el compilador NO proporcionara un constructor sin argumentos (o
cualquier otro constructor). Es decir si hemos escrito algn constructor con argumentos no vamos a
tener un constructor sin argumentos a menos que nosotros mismos lo declaremos.
Todos los constructores tienen como primera declaracin ya sea una llamada a un
constructor sobre cargado "this()" o una llamada al constructor de la superclase "super()",
aunque recuerden que esta llamada puede ser insertada por el compilador.
Si escribimos un constructor (en lugar de confiar en el constructor por defecto generado
por el compilador), y no escribimos una llamada a this() o a super(), el compilador insertar
una llamada sin argumentos a super() por nosotros, como una primera declaracin en el
constructor.
Una llamada a super() puede ser una llamada sin argumentos o podemos incluir
argumentos en l.
Un constructor sin argumentos no es necesariamente el constructor por defecto, aunque el
constructor por defecto siempre es uno sin argumentos. El constructor por defecto es el nico que
el compilador provee, pero podemos insertar nuestro propio constructor sin argumentos.
No podemos hacer una llamada a un mtodo de instancia o acceder a una variable de
instancia hasta que se ejecute el constructor super.
Solo variables y mtodos estticos pueden ser accedidos como parte de la llamada
a super() o this(). Por ejemplo: super(Animal.NOMBRE) est bien ya que NOMBRE est
declarada como variable esttica.
Las clases abstractas tienen constructores, y estos constructores son siempre llamados
cuando una clase concreta es instanciada.
Las interfaces no tienen constructores, las interfaces no son parte del rbol de herencia
de un objeto.
La nica forma de que un constructor pueda ser invocado es dentro de otro constructor, en
decir, no podemos invocar a un constructor de la siguiente manera:

public class Perro
{
public Perro(){} //Contructor

public void hacerAlgo()
{
Perro(); //llamada al constructor. Error!!
}
}

Determinar si un constructor por defecto ser creado
El siguiente cdigo muestra a la clase "Perro" con dos constructores:

public class Perro
{
public Perro(){}
public Perro(String nombre){}
}


El compilador insertar un constructor por defecto para la clase anterior? NO!!

Y para la siguiente modificacin en la clase?

public class Perro
{
public Perro(String nombre){}
}


Ahora el compilador insertar un constructor por defecto? NO!!

Y qu hay de esta clase?

public class Perro
{
}


El compilador SI generar un constructor por defecto para la clase anterior, porque la clase no
tiene ningn constructor definido. Y ahora Qu hay de esta siguiente clase?:

public class Perro
{
void Perro(){}
}


Podra parecer que el compilador no crea un constructor ya que ya hay un constructor en la clase
"Perro". Pero realmente hay un constructor? Revisemos nuevamente la clase anterior, pues eso
no es un constructor, es solo un mtodo que tiene el mismo nombre que la clase. Recordemos
que el tipo de retorno es un claro indicador de que eso es un mtodo y no un constructor.

Cmo se sabe con seguridad que un constructor por defecto ser creado?

Porque no declaramos NINGUN constructor en nuestra clase.

Cmo se ver el constructor por defecto creado por el compilador?
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 sper constructor
(super()).


Qu sucede si el sper constructor tiene argumentos?

Los constructores pueden tener argumentos as como los mtodos, si tratamos de invocar a un
mtodo que toma por ejemplo un int y no le pasamos nada al mtodo, el compilador se
comportar de la siguiente manera:

class Ejemplo
{
void tomaUnInt(int valor){}
}

class Test
{
public static void main(String args)
{
Ejemplo e = new Ejemplo();
e.tomaUnInt(); //Se est tratando de invocar al metodo
"tomaUnInt()" sin argumentos
}
}


El compilador nos dir que estamos tratando de invocar a "tomaUnInt()" sin pasarle ningn
un int. El compilador, segn la versin de la JVM, responder ms o menos de la siguiente
manera:

Test.java:7: tomaUnInt(int) in Ejemplo cannot be applied to ()e.
tomaUnInt();


Esto quiere decir que debemos pasar los mismos valores o variables que el mtodo acepta y en el
mismo orden en el que est declarado en el mtodo, a lo que queremos llegar es que este
mecanismo funciona exactamente igual en los constructores.

A continuacin mostramos el cdigo que genera el compilador con respecto a los constructores:
Cdigo de clase (lo que nosotros
escribimos)
Cdigo de constructor generado por el
compilador
class Perro { }

class Perro
{
Perro()
{
super();
}
}


class Perro
{
Perro(){}
}

class Perro
{
Perro()
{
super();
}
}
public class Perro { }

public class Perro
{
public Perro()
{
super();
}
}

class Perro
{
Perro(String nombre){}

class Perro
{
Perro(String nombre)
Cdigo de clase (lo que nosotros
escribimos)
Cdigo de constructor generado por el
compilador
} {
super();
}
}

class Perro
{
Perro(String nombre)
{
super();
}
}
Nada, el compilador no necesita insertar nada

class Perro
{
void Perro(){}
}

class Perro
{
void Perro(){}

Perro()
{
super();
}
}


("void Perro()", es un mtodo no un
constructor)


Si el sper constructor (el constructor de su inmediata sper clase o clase padre) tiene argumentos,
debemos escribir en la llamada asuper() los argumentos adecuados.

Un punto crucial: si nuestra superclase no tiene un constructor sin argumentos, debemos escribir
un constructor en la clase (subclase), porque necesitamos un lugar donde insertar, en la llamada
a super, los argumentos adecuados.

El siguiente cdigo da un ejemplo del problema:

class Animal
{
Animal(String nombre){}
}

class Perro extends Animal
{
Perro()
{
super(); //He aqu el problema
}
}


El compilador nos arrojar algo como esto:

Perro.java:7: cannot resolve symbol
symbol : constructor Animal ()
location: class Animal
super(); // Problema!
^


Otra forma de explicar es la siguiente: Si nuestra superclase no tiene un constructor sin
argumentos entonces la subclase no ser capaz de usar el constructor por defecto que te provee el
compilador, es decir, el compilador puede solo insertar una llamada a "super()" sin argumentos,
no ser capaz de compilar algo como esto:

class Animal
{
Animal(String nombre){}
}

class Perro extends Animal{}


El compilador nos arrojar algo como esto:

Animal.java:4: cannot resolve symbol
symbol : constructor Animal ()
location: class Animal
class Perro extends Animal { }
^


El compilador explcitamente est haciendo el cdigo que se muestra a continuacin, donde vamos
a proveer a "Perro" el mismo constructor que el compilador le proveer:

class Animal
{
Animal(String nombre){}
}

class Perro extends Animal
{
//el constructor a continuacin es idntico al que el compilador
proveer
Perro()
{
super(); //Se invoca al constructor sin argumentos de "Animal"
el cual no existe!!
}
}


Una ltima cosa que debemos recordar es que los constructores no se heredan, estos no son
mtodos los cuales si se heredan. Estos no pueden ser sobre-escritos pero, como hemos visto a lo
largo de esta parte de constructores, estos si se pueden sobrecargar.

Sobrecarga de constructores
Sobrecargar un constructor quiere decir que escribimos diferentes versiones del constructor, cada
uno tiene diferente nmero de argumentos, como por ejemplo:

class Perro
{
Perro(){}

Perro(String nombre){}
}


La clase "Perro" anterior muestra dos constructores sobrecargados, uno de ellos toma
un String como argumento y el otro no tiene argumentos; este es exactamente igual al
constructor que el compilador provee, pero recordemos que una vez que nosotros escribamos un
constructor en la clase, como por ejemplo el que toma el String, el compilador ya no nos
proveer un constructor por defecto. Si queremos un constructor sin argumentos para sobrecargar
el que tiene argumentos nosotros mismo tendremos que escribirlo como en el ejemplo anterior.

Sobrecargando un constructor proveemos diferentes maneras de que se pueda instanciar un
objeto de nuestra clase, por ejemplo si sabemos el nombre del Perro, podemos pasarselo a un
constructor de "Perro" que toma una cadena. Pero si no sabemos el nombre podemos llamar al
constructor sin argumentos para que nos provea un nombre por defecto, a continuacin mostramos
un ejemplo de lo que estamos hablando:

1. public class Perro {
2. String nombre;
3. Perro (String nombre){
4. this.nombre = nombre;
5. }
6.
7. Perro(){
8. this(tomaNombreAleatorio());
9. }
10.
11. static String tomaNombreAleatorio(){
12. int x = (int) (Math.random() * 5);
13. String nombre = new String[]{"fido", "tango", "aguao",
"rex" , "lassy"}[x];
14. return nombre;
15. }
16.
17. public static void main(String args){
18. Perro a = new Perro();
19. System.out.println(a.nombre);
20. Perro b = new Perro("flafy");
21. System.out.println(b.nombre);
22. }
23. }


Ejecutando el cdigo unas cuantas veces tendremos un resultado como el siguiente:

% java Perro
tango
flafy
% java Perro
lassy
flafy
% java Perro
rex
flafy
% java Perro
aguao
flafy


A continuacin mostramos la pila de llamadas para la invocacin del constructor cuando un
constructor es sobrecargado.
4. Object
3. Perro(String nombre) llamada a super()
2. Perro() llamada a this(tomaNombreAleatorio())
1. main() llamada a new Perro()


Ahora vamos a describir el cdigo desde la parte superior:
Lnea 2: declaramos una variable de instancia nombre de tipo String
Lnea 3 5: El constructor toma un String y lo asigna a la variable de instancia nombre
Lnea 7: Aqu viene lo interesante. Asumiendo que cada Animal necesita de un nombre,
pero la persona que lo invoca no siempre debe saber que nombre ser (cdigo de llamada),
entonces nosotros establecemos un nombre aleatorio. El constructor sin argumentos genera un
nombre aleatorio invocando al mtodo "tomaNombreAleatorio()".
Lnea 8: El constructor sin argumentos invoca a su propio constructor sobrecargado que
toma un String llamandolo de la misma manera que sera llamado si se hace una nueva
instancia del objeto, pasndole un String para el nombre. La invocacin al constructor
sobrecargado se hace mediante la palabra reservada "this", pero la utiliza como si fuese un
nombre de mtodo, this(). Entonces en la lnea 8 simplemente se est llamando al constructor
sin parmetros que est en la lnea 3, pasndole un nombre aleatorio en lugar nosotros establecer
el nombre.
Lnea 11: Notemos que el mtodo "tomaNombreAleatorio()" est marcado como
esttico (static), eso es porque no podemos invocar a un mtodo de instancia (en otras
palabras, no esttico) o acceder a una variable de instancia hasta despus de que el super
constructor haya sido ejecutado, y hasta que el sper constructor sea invocado desde el
constructor en la lnea 3, en lugar que de la lnea 7, la lnea 8 puede usar solo un mtodo esttico
para generar un nombre. Si nosotros quisiramos especificar algn nombre en especfico en vez
de que se genere aleatoriamente, por ejemplo, "Thor", entonces en la lnea 8 simplemente
pondramos this("Thor") en lugar de llamar al mtodo "tomaNombreAleatorio()" para
generar un nombre aleatorio.
Lnea 12: Esto no tiene nada que ver con el constructor pero es bueno aprenderlo, esto
genera un numero entero aleatorio entre 0 y 4;

Lnea 13: Estamos creando un nuevo String, pero queremos que este String sea seleccionado
aleatoriamente desde una lista, entonces necesitamos hacer esto. Para explicarlo con mejor
detalle, en esta sola lnea de cdigo hacemos lo siguiente:
1. 1. Declaramos una variable del tipo String.
2. 2. Creamos un arreglo de Strings (annimo ya que no asignamos el arreglo)
3. 3. Obtenemos el String en index [x] (x contiene el numero aleatorio generado
en la lnea 12) del recientemente creado arreglo de Strings.
4. 4. Asignamos el String obtenido del arreglo a la variable de instancia "nombre".
Esto hubiera sido ms fcil de leer si hubiramos escrito esto:

String[] lista = {"fido", "tango", "aguao", "rex" , "lassy"};
String nombre = lista[x];

Lnea 18: Invocamos al constructor sin argumentos (generando un nombre aleatorio que
despus ser enviado al constructor que recibe un String).
Lnea 20: Invocamos al constructor sobrecargado que toma un String que representa
el nombre.


El punto cable en el cdigo antes escrito est en la lnea 8, en lugar de llamar a super(), estamos
llamando a "this()", y "this()" siempre significa llamar a otro constructor en la misma clase.
Pero qu sucede al momento de llamar a "this()"? Tarde o temprano el constructor "super()"
ser llamado, una llamada a "this()" solo significa que estamos retrasando lo inevitable, ya que
algn constructor en algn lugar debe hacer una llamada a "super()".

La regla clave: la primera lnea de un constructor debe ser una llamada a "super()" o una
llamada a "this()".

Sin excepciones. Si el constructor "A()" tiene una llamada a "this()", el compilador sabe que el
constructor "A()" no ser e que invoque a "super()".

La regla anterior significa que un constructor nunca podr tener ambas llamadas, es decir no podr
llamar a la vez a "this()" y a "super()". Porque alguna de estas llamadas debe ser la primera
sentencia en un constructor, no podemos usar ambas en un mismo constructor. El compilador
tampoco insertar una llamada a "super()" si el constructor tiene una llamada a "this()".

Qu suceder si nosotros tratamos de compilar el siguiente cdigo?

class A
{
A()
{
this("test");
}

A(String s)
{
this();
}
}


El compilador puede que no capte el problema (esto depende del compilador). Este asume que
sabemos lo que estamos haciendo. Captan el problema? Sabemos que el sper constructor
siempre debe de ser llamado, entonces Dnde podra ir la llamada a "super()"? Recordemos
que el compilador no inserta ningn constructor por defecto si nosotros ya insertamos uno o ms
constructores en nuestra clase, y cuando el compilador no inserta un constructor por defecto
todava puede insertar una llamada a super() en algn constructor que no tenga explcitamente
una llamada a super(), a menos que, el constructor ya tenga una llamada a this() y
recordemos que un constructor no puede tener ambas llamadas (this() y super()). Entonces
en el cdigo anterior Dnde va la llamada a super()? Si los nicos dos constructores en la clase
tienen una llamada a this(), en efecto nosotros tenemos el mismo problema que tendramos si
escribimos los siguientes mtodos:

public void ir()
{
hacerAlgo();
}

public void hacerAlgo()
{
ir();
}


Ahora pueden ver el problema? Podemos ver que el stack explota. Ya que se llamaran uno a otro
indefinidamente hasta que la maquina o la JVM estalle (esperamos que lo segundo suceda
primero o lo primero?). Regresando al ejemplo de los constructores podemos decir que dos
constructores sobrecargados y ambos con una llamada a this() son dos constructores
llamndose uno a otro una y otra y otra vez, resultando en:

% java A
Exception in thread "main" java.lang.StackOverflowError


El beneficio de tener constructores sobrecargados es que ofrecen formas flexibles de poder
instanciar un objeto de nuestra clase. El beneficio de que un constructor invoque a otro constructor
sobrecargado es evitar duplicacin de cdigo, en el ejemplo anterior no hubo algn otro cdigo
para establecer el nombre, pero imaginen que despus de la lnea 4 an hay muchas cosas que
podramos hacer.

Variables y mtodos estticos
El modificador "static" tiene un impacto tan profundo en el comportamiento de un mtodo o una
variable que debemos tratando como un concepto totalmente separado de los dems
modificadores. Para entender la manera en que un miembro esttico trabaja, primero veremos las
razones por las cuales utilizaramos alguno.

Imaginen que tenemos una clase de utilidad la cual siempre se ejecuta de la misma manera, su
nica funcin es devolver, digamos, un nmero al azar. No nos importa en cul instancia de la
clase se ejecuta el mtodo, ya que siempre se comporta de la misma manera. En otras palabras, el
comportamiento del mtodo no tiene ninguna dependencia en el estado (valores de variable de
instancia) de un objeto. Entonces Porque es necesario un objeto cuando el mtodo nunca ser
instanciado? Por qu no solo pedimos a la clase en si misma que ejecute el mtodo?

Ahora imaginemos otro escenario: supongamos que queremos mantener un contador corriendo
para todas las instancias de una clase en particular. En dnde incluiremos la variable? No va a
trabajar si la incluimos como variable de instancia dentro de las clases en las cuales se quiere
hacer el seguimiento, ya que el contador siempre se iniciara a un nuevo valor por defecto cada que
nosotros creamos una nueva instancia.

La respuesta a los dos escenarios anteriores (el mtodo de utilidad que se ejecuta siempre de la
misma manera, y el contador para mantener el total de instancias actualizado) es utilizar el
modificador static.

Las variables y mtodos marcados con static pertenecen a la clase y no a una instancia en
particular. Podemos usar un mtodo o variable static sin tener instancias de esa clase, solo
necesitamos que la clase est disponible para invocar un mtodo static o acceder a una
variable static.

Una variable esttica de una clase ser compartida por todas las instancias de esa clase, slo hay
una copia.

El siguiente cdigo utiliza una variable static que ser utilizada como contador:

class Oveja
{
static int contadorOvejas = 0; //Declaramos e inicializamos la
variable esttica

public Oveja()
{
contadorOveja += 1; //Modificamos el valor en el constructor
}

public static void main(String args)
{
new Oveja();
new Oveja();
new Oveja();

System.out.println("El contador de ovejas est ahora en: " +
contadorOveja);
}
}


En el cdigo anterior, la variable esttica "contadorOveja" es establecida en cero cuando la
clase "Oveja" es cargada por primera vez por la JVM, antes de que cualquier instancia de "Oveja"
sea creada (en realidad no se necesita inicializar la variable esttica en cero, las variable estticas
obtienen los mismos valores por defecto que las variables de instancia obtienen). Cada vez que
una instancia de la clase "Oveja" es creada el constructor de "Oveja" es ejecutado y la variable
"contadorOveja" es incrementada. Cuando este cdigo es ejecutado, tres instancias de "Oveja"
son creadas en el "main()", y el resultado es el siguiente:

El contador de ovejas est ahora en: 3


Ahora imaginemos que sucedera si la variable "contadorOveja" fuera una variable de instancia
(es decir, una variable no esttica):

class Oveja
{
int contadorOvejas = 0; //Declaramos e inicializamos la variable de
instancia

public Oveja()
{
contadorOveja += 1; //Modificamos el valor en el constructor
}

public static void main(String... args)
{
new Oveja();
new Oveja();
new Oveja();

System.out.println("El contador de ovejas est ahora en: " +
contadorOveja);
}
}


Cuando este cdigo es ejecutado, este puede todava crear tres instancias de la clase "Oveja" en
el "main()", pero el resultado es un error de compilacin. No podemos compilar este cdigo,
mucho menos ejecutarlo, porque obtenemos el siguiente error:

Exception in thread "main" java.lang.RuntimeException: Uncompilable
source code - non-static variable contadorOveja cannot be referenced
from a static context
System.out.println("El contador de ovejas est ahora en: " +
contadorOveja);
^


La JVM no sabe a cul objeto "contadorOveja" de "Oveja" estamos intentando de acceder. El
problema est en que el mtodo "main()" en s mismo es un mtodo esttico. Un mtodo esttico
no puede acceder a una variable no esttica (variable de instancia) porque hay que recordar que
para acceder a una variable esttica no se necesita una instancia de la clase, ya que la variable
pertenece a la clase misma.

Eso no quiere decir que no hay instancias de la clase con vida en la heap, si las hay, pero el
mtodo esttico no sabe nada de ellas.

Lo mismo se aplica a los mtodos de instancia, un mtodo esttico no pueden invocar
directamente un mtodo no esttico.

Piensen que static=clase, no-esttico=instancia. Haciendo que el mtodo llamado por
la JVM ("main()") sea un mtodo esttico laJVM no tiene que crear una instancia de la clase slo
para iniciar la ejecucin de cdigo.

Accediendo a mtodos y variables estticos
Puesto que no es necesario tener una instancia para invocar un mtodo esttico o acceder a una
variable esttica, entonces cmo invocar o utilizar un miembro esttico? Cul es la sintaxis?
Sabemos que con un mtodo de instancia regular, se utiliza el operador punto "." en una
referencia, por ejemplo:

class Oveja
{
static int contadorOvejas = 0; //Declaramos e inicializamos la
variable esttica

public Oveja()
{
contadorOveja += 1; //Modificamos el valor en el constructor
}

public static void main(String... args)
{
new Oveja();
new Oveja();
new Oveja();
System.out.println("El contador de ovejas est en: " +
Oveja.contadorOveja);
}
}


Pero para que sea realmente confuso, el lenguaje Java tambin permite el uso de una variable de
referencia de objeto para acceder a un miembro esttico:

Oveja ov = new Oveja();
ov.contadorOveja; //Accediendo a la variable esttica contadorOveja
usando o


En el cdigo anterior, hemos instanciado una "Oveja" asignando "new Oveja" a la variable de
referencia "ov", y despus usamos la referencia "ov" para invocar al mtodo esttico. Pero a pesar
de que se est utilizando una instancia especfica para acceder al mtodo esttico, las reglas no
han cambiado. Esto no es ms que un truco de sintaxis que nos permite utilizar una variable de
referencia a objeto (pero no el objeto que se refiere) para llegar a un mtodo o variable esttica,
pero el miembro esttico sigue ignorando la instancia utiliza para invocar al miembro esttico. En el
ejemplo de la Oveja, el compilador sabe que la variable de referencia "ov" es del tipo de Oveja,
por lo que el mtodo esttico de la clase Oveja se ejecuta sin conocimiento o inters para la
instancia de la Oveja del otro extremo de la referencia "ov". En otras palabras al compilador le
importa solo que la variable de referencia "ov" sea del tipo Oveja.

El compilador en realidad hace una transformacin a la llamada que acabamos de hacer. Cuando
ve que estamos tratando de invocar a un miembro esttico, reemplaza la variable de instancia que
estamos usando por la clase en la que est dicho miembro. Esto quiere decir que reemplazara esta
llamada:

Oveja ov = new Oveja();
ov.contadorOveja;


Por esta otra:

Oveja ov = new Oveja();
Oveja.contadorOveja;


As que como podemos ver, finalmente quedamos con una llamada al miembro esttico, a travs
de la clase a la que pertenece dicho miembro.

La siguiente imagen describe el efecto del modificador static en mtodos y variables:



Finalmente, recuerden que los mtodos estticos no pueden ser sobrescritos. Pero esto no
significa que no puedan ser redefinidos en una subclase. Redefinir y sobrescribir no son la misma
cosa. A continuacin mostramos un ejemplo sobre redefinir (no sobrescribir) un mtodo marcado
como static:

class Animal
{
static void hacerAlgo()
{
System.out.println("a");
}
}

class Perro extends Animal
{
static void hacerAlgo()
{
System.out.println("b"); //Esto es redefinir, no sobrescribir
}

public static void main(String... args)
{
Animal[] a = {new Animal(), new Perro(), new Animal()};

for(int i = 0; i < a.length; i++ )
{
a[i].hacerAlgo(); //Invoca al mtodo esttico
}
}
}


Ejecutando el cdigo anterior se produce la siguiente salida:

a a a


Recuerden, la sintaxis "a[i].hacerAlgo()" es solo un atajo (un truco de sintaxis). El compilador
lo sustituye con algo como "Animal.hacerAlgo()", como vimos hace un momento.

Cohesin y acoplamiento (Coupling and
Cohesion):
Estos dos temas, la cohesin y el acoplamiento, tienen que ver con la calidad de un diseo
orientado a objetos. En general un buen diseo pide un acoplamiento bajo y evita un
acoplamiento estrecho y un buen diseo orientado a objetos pide una alta cohesin y evita la baja
cohesin. Como con la mayora de las discusiones sobre diseo de orientacin a objetos, las
metas de una aplicacin son:
Facilidad de creacin.
Facilidad de mantenimiento.
Facilidad de mejora.


Acoplamiento
Vamos a empezar haciendo un intento sobre la definicin de acoplamiento. Acoplamiento es el
grado en el cual una clase sabe acerca de otra clase. Si el nico conocimiento que la clase "A"
tiene acerca de la clase "B", es lo que la clase "B" ha puesto de manifiesto a travs de su interface,
se dice que la clase "A" y "B" estn dbilmente acopladas, lo cual es algo bueno. Si por otro lado, la
clase "A" se basa en una parte de la clase "B", que no es parte de la interface de la clase "B",
entonces el acoplamiento entre estas dos clases es ms estrecho, y esto no es algo bueno. En
otras palabras, si la clase "A" sabe ms de lo que debera de la forma en que se implement "B",
entonces "A" y "B" estn estrechamente acopladas.

Usando este segundo escenario, imaginemos lo que sucede cuando la clase "B" sea mejorada. Es
muy posible que el desarrollador que mejore a "B" no tenga conocimiento acerca de "A" Y porque
debera de tenerlo? El desarrollador de la clase "B" debe pensar (y es correcto) que todas las
mejoras que no quiebren o rompan la interfaz de la clase deben ser seguras, por lo que podra
cambiar alguna parte que no tenga que ver con la interface en la clase. Si las dos clases estn
estrechamente acopladas, este cambio provocara que la clase "A" se quiebre.

Veamos un ejemplo obvio de acoplamiento fuerte, que ha sido posible gracias a una pobre
encapsulacin:

class Impuestos
{
float ratio;

float calculaImpuestoVentaPeru()
{
RatioImpuestoVentas riv = new RatioImpuestoVentas();
ratio = riv.ratioVentas; /*Mal, esto debera ser una llamada a
un
mtodo get para obtener la variable,
por ejemplo:
ratio = riv.getRatioVentas("PE");
*/
}
}

class RatiosImpuestoVentas
{
public float ratioVentas; //Debera ser privado
public float ajusteRatioVentas; //Debera ser privado

public float getRatioVentas(String pais)
{
ratioVentas = new Impuestos().calculaImpuestoVentaPeru(); //Mal
otra vez hacer basado en los clculos de la regin.

return ajusteRatioVentas;
}
}


Todas las aplicaciones orientadas a objetos que no son triviales son una mezcla de muchas clases
e interfaces trabajando juntas. Idealmente, todas las interacciones entre los objetos en un sistema
orientado a objetos deben utilizar sus APIs, en otras palabras, los contratos de las clases de los
objetos respectivos. Tericamente, si todas las clases en una aplicacin tienen bien diseada sus
APIs, entonces debera ser posible para todas las interacciones entre las clases el uso de las APIs
de forma exclusiva. Como hemos comentado anteriormente en este captulo, un aspecto de buen
diseo de una clase y el diseo de la API es que las clases deben estar bien encapsuladas.

Cohesin
Mientras que el acoplamiento tiene que ver con cmo las clases interactan con las otras clases, la
cohesin es acerca de cmo una simple clase es diseada. El termino cohesin es usado para
indicar el grado para el cual una clase tiene un propsito simple bien enfocado . Hay que
mantener en mente que la cohesin es un concepto subjetivo al igual que el acoplamiento. Cuanto
ms enfocada sea la clase en una sola tarea, mayor su cohesin, lo cual es bueno. El beneficio
clave de la alta cohesin, es que estas clases son mucho ms fciles de mantener (y menos
frecuentes a ser cambiadas) que las clases con baja cohesin. Otro beneficio de la alta cohesin
es que las clases con un propsito bien enfocado tienden a ser ms reutilizables que otras clases.
Veamos un ejemplo:

class ReportePresupuesto
{
void conectarBaseDatos(){}
void generarReportePresupuesto(){}
void guardarArchivo(){}
void imprimir(){}
}


Ahora imaginen que su jefe llega y dice, "Eh, sabes de la aplicacin de contabilidad que estamos
trabajando? Los clientes decidieron que tambin van a querer generar un informe de proyeccin de
ingresos, y que quieren hacer algunos informes de inventario tambin".

Tambin les dice que se aseguren de que todos estos informes les permitan elegir una base de
datos, seleccione una impresora, y guardar los informes generados a ficheros de datos ... Ouch!

En lugar de poner todo el cdigo de impresin en una clase de informe, probablemente hubiera
sido mejor usar el siguiente diseo desde el principio:

class ReportePresupuesto
{
Opciones getOpcionesReporte() {}
void generarReportePresupuesto(Opciones o){}
}

class ConexionBaseDatos
{
ConexionBD getConexion(){}
}

class Impresion
{
OpcionesImpresion getOpcionesImpresion(){}
}

class AlmacenArchivos
{
OpcionesGuardado getOpcionesGuardado(){}
}


Este diseo es mucho ms cohesivo. En lugar de una clase que hace todo, hemos roto el sistema
en cuatro clases principales, cada uno con un rol muy especfico (cohesin).

Como hemos construido estas clases especializadas, reutilizables, y va a ser mucho ms fcil
escribir un nuevo informe, dado que ya tenemos la clase de conexin de bases de datos, la clase
de impresin, y la clase para guardar archivos, y eso significa pueden ser reutilizados por otras
clases pueden desear imprimir un informe.

Este es el fin del segundo tutorial, donde hemos aprendido un poco sobre algunos de los
conceptos ms importantes de la orientacin a objetos que son necesarios para el examen de
certificacin, y para nuestra vida como programadores en general.El la prxima entrega
seguiremos aprendiendo ms temas importantes para nosotros como programadores Java y en
particular para los que deseen certificarse como programadores Java.

Muchas gracias a Alan Cabrera Avanto, de Trujillo Per por este tutorial.

También podría gustarte