LA relación "Es un" y "Tiene un"
La relacion "es un" habla simpre de herencia y puede explicarse atraves de una frase simple como "es auto ES UN medio de transporte" como puedes darte cuenta auto es un subtipo de medio de transporte, en este caso podriamos decir que medio de transporte es la superclase y auto es la subclase:
caracteristicas (atributos) de Medios de Transporte:
-trasladan cosas, personas, animales.
-puede ser aéreo, terrestre, marítimo
-recorre un camino con punto de inicio y final.
características(atributos) de Autos;
-trasladan cosas, personas, animales.
-es terrestre.
-recorre un camino con punto de inicio y final.
-tiene un volante-
-puede ser manual o automático
-acelera y frena
Como puedes ver "medios de transporte" podría considerarse como una plantilla que podria definirse a si misma y a sus atributos, pero también serviría para crear especificaciones de si misma, a través de la creación de clases que describan por ejemplo a; autos, aviones, helicópteros, barcos etc...
En este caso describimos auto para hacer notar que comparte características de medios de transporte, pero no podríamos declarar un auto simplemente como medio de transporte ya que tiene detalles que no podrían especificarse en ella, como por ejemplo ; si es automático o manual, que es terrestre, etc... no podríamos poner como atributos estas cosas en medios de transporte ya que tenemos, por ejemplo, un avion que no es terrestre.
En contraste la relación "tiene un " hace referencia a la composición (que ya veremos en detalle) es decir a los atributos propios de la clase, por ejemplo un auto "tiene un" máximo de velocidad. por lo general estos atributos de clase suelen especificarse mediante "static"
Alcance de las variables y clases en la herencia
ya hablamos en otras entradas sobre los modificadores de acceso, Es importante a esta altura recordarlo para utilizar lo aprendido en el campo de la herencia.
hablamos sobre los miembros public de una clase que pueden ser vistos desde cualquier otra clase, del mismo u otro paquete. tambien hablamos sobre los miembros private que solo son visibles desde la clase en que se declaran ESTE TIPO DE VARIABLES NO SE HEREDAN. y miembros protected que tienen un nivel de acceso intermedio, estos miembros pueden ser vistos por las clases heredadas y por las demas clases del mismo paquete en que se declaran.
*A pesar de no tenemos visibilidad desde una subclase d elos miembros private de la superclase, si podemos modificar dichas variables a través de métodos public heredados de la superclase.
*Se declaran variables private para proteger al máximo los valores de las mismas de la intrucion no permitida.
*El compilador establece de forma automática a Object como la clase predeterminada en caso de no encontrar alguno otra clase declarada como superclase de la nuestra.
ej:
public class Animal {
private String tipo;//se establece como private para que no pueda ser cambiada desde la subclase
public void establecerNombre(String tipo)//establece el nombre del animal
{
this.tipo = tipo;
}
public void mensaje()
{
System.out.println("Tu animal es un "+tipo);
}
public void camina()
{
System.out.println(tipo+" camina");
}
public void vuela()
{
System.out.println(tipo+" vuela");
}
}
en esta clase, puse metodos publicos, uno para establecer el nombre o tipo de animal y otras para mostrar mensajes respecto al tipo de animal
public class Perro extends Animal{ //subclase de animal
Perro() //creamos un constructor para poder llamar a los metodos de la superclase
{
this.establecerNombre("perro"); //establesco el tipo de animal
this.mensaje(); //llamamos solo a los metodos que utilizaremos de la super clase
this.camina();
}
public static void main(String[]args)
{
Perro ini = new Perro();
}
}
por ejemplo, en la superclase a hay un método que se llama vuela, como nuestro animal (perro) no vuela, no utilizaremos este método, pero podríamos crear otra clase llamada "Pajaro" que si va a necesitar el metodo vuela().
(En la superclase podriamos haber puesto infinidad de metodos para aludir a acciones)
la salida de este programa seria asi:
run:
Tu animal es un perro
perro camina
BUILD SUCCESSFUL (total time: 0 seconds)
La herencia no solo nos permite llamar a los métodos o atributos de una clase, sino que tambien podemos sobre escribirlos
por ejemplo, en la superclase animal esta el método
public void mensaje()
{
System.out.println("Tu animal es un "+tipo);
}
Al cual llamamos desde el constructor de la subclase Perro, pero que pasa si quisieramos modificar ese mensaje?? pues podríamos hacerlo asi, Desde la clase perro sobreescribimos el metodo mensaje() lo que nos quedaría asi.
public class Perro extends Animal{
Perro()
{
this.establecerNombre("perro");
mensaje();
this.camina();
}
public void mensaje()
{
System.out.println("tu animal es el mejor amigo del hombre");
}
public static void main(String[]args)
{
Perro ini = new Perro();
}
}
//al hacer esto estamos sobrescribiendo el metodo mensaje() (el compilador nos mostrara un mensaje de advertencia diciendonos que estamos sobreescribiendo un metodo de la super clase). fijense que en el constructor de perro elimine el this y llame al metodo solo con el nombre.
la salida de este programa seria esta :
run:
tu animal es el mejor amigo del hombre
perro camina
BUILD SUCCESSFUL (total time: 1 second)
Como tercera opcion tambien podemos sobreescribir un metodo de la superclase y al mismo tiempo llamar a dicho metodo a traves de la palabra clave super. Con super podemos llamar al metodo o constructor de la superclase, para ello debemos estar en el metodo sobrescrito o en el constructor. Para ello modificaremos unas simples lineas de nuestra clase perro.
public class Perro extends Animal{
Perro()
{
this.establecerNombre("perro");
mensaje();
this.camina();
}
public void mensaje()
{
super.mensaje();
System.out.println("tu animal es el mejor amigo del hombre");
}
public static void main(String[]args)
{
Perro ini = new Perro();
}
}
//Si te fijas, este codigo es casi igual al anterios, lo unico diferente es que tiene la sentencia super.mensaje();
lo cual hace un llamado al metodo original, lo ejecuta y despues continua con el codgio dentro del metodo sobreescrito.
La salida seria la siguiente.
run:
Tu animal es un perro
tu animal es el mejor amigo del hombre
perro camina
BUILD SUCCESSFUL (total time: 0 seconds)
si te fijas, se ha agregado a la salida la linea de código del método mensaje original al cual llamamos mediante super.
*Es un error de compilación sobrescribir un método con un modificador de acceso más restringido; un método public de la superclase no puede convertirse en un método protected o private en la subclase; un método protected de la superclase no puede convertirse en un método private en la subclase. Hacer esto sería quebrantar la relación es un, en la que se requiere que todos los objetos de la subclase puedan responder a las llamadas a métodos que se hagan a los métodos public declarados en la superclase. Si un método public pudiera sobrescribirse como protected o private, los objetos de la subclase no podrían responder a las mismas llamadas a métodos que los objetos de la superclase. Una vez que se declara un método como public en una superclase, el método sigue siendo public para todas las subclases directas e indirectas de esa clase.
*Llamar a un metodo o constructor de la superclase con un numerod e argumentos y tipos diferentes de los requeridos produce un error de compilacion.
*Es recomendable no usar variables protected, en vez de eso utiliza variables private y especifica metodos public para modificar dichas variables.
*si queremos llamar a un metodo de la superclase desde un metodo sobrescrito de la subclase, debemos asegurarnos de llamarlo con la palabra clave super y un punto. ya que de no hacerlo se genera una recursividad infinita, en la que el metodo se llame asi mismo, hasta agotar la memoria.
miMetodo() //metodo sobreescrito de la superclase
{
miMetodo(); // sin super, provoca recursividad ya que el metodo se llama a si mismo.
}
asi se hace correctamente.
miMetodo()
{
super.miMetodo(); //llama al metodo de la super clase.
}
La recursividad infinita e suna poderosa herramienta que veremos mas adelante.
La clase Object
Como ya hemos dicho varias veces todas las clases en java heredan de la Clase Object, y con ello obtienen sus 8 metodos, puedes probarlo creando una clase e instanciandola, pones el nombre de la instancia y un punto y te saldran los 11 metodos heredados de object.
clone()
Este método protected, que no recibe argumentos y devuelve una referencia Object, realiza una copia
del objeto en el que se llama. Cuando se requiere la clonación para los objetos de una clase, ésta debe
sobrescribir el método clone como un método public, y debe implementar la interfaz Cloneable
(paquete java.lang). La implementación predeterminada de este método realiza algo que se conoce
como copia superfi cial: los valores de las variables de instancia en un objeto se copian a otro objeto del
mismo tipo. Para los tipos por referencia, sólo se copian las referencias. Una implementación típica
del método clone sobrescrito sería realizar una copia en profundidad, que crea un nuevo objeto para
cada variable de instancia de tipo por referencia. Hay muchos detalles sutiles en cuanto a sobrescribir el
método clone. Puede aprender más acerca de la clonación en el siguiente artículo:
java.sun.com/developer/JDCTechTips/2001/tt0306.html
equals()
Este método compara la igualdad entre dos objetos; devuelve true si son iguales y false en caso contrario.
El método recibe cualquier objeto Object como argumento. Cuando debe compararse la igualdad
entre objetos de una clase en particular, la clase debe sobrescribir el método equals para comparar
el contenido de los dos objetos. La implementación de este método debe cumplir los siguientes requerimientos:
• Debe devolver false si el argumento es null.
• Debe devolver true si un objeto se compara consigo mismo, como en objeto1.equals( objeto1 ).
• Debe devolver true sólo si tanto objeto1.equals( objeto2 ) como objeto2.equals( objeto1 )
devuelven true.
• Para tres objetos, si objeto1.equals( objeto2 ) devuelve true y objeto2.equals( objeto3 )
devuelve true, entonces objeto1.equals( objeto3 ) también debe devolver true.
• Si equals se llama varias veces con los dos objetos, y éstos no cambian, el método debe devolver true
de manera consistente si los objetos son iguales, y false en caso contrario.
Una clase que sobrescribe a equals también debe sobrescribir hashCode para asegurar que los objetos
iguales tengan códigos de hash idénticos. La implementación equals predeterminada utiliza el operador
== para determinar si dos referencias se refi eren al mismo objeto en la memoria. La sección 30.3.3
demuestra el método equals de la clase String y explica la diferencia entre comparar objetos String
con == y con equals,
finalize()
El recolector de basura llama a este método protected para
realizar las tareas de preparación para la terminación en un objeto, justo antes de que el recolector de
basura reclame la memoria de ese objeto. No se garantiza que el recolector de basura vaya a reclamar un
objeto, por lo que no se puede garantizar que se ejecute el método finalize del objeto. El método debe
especifi car una lista de parámetros vacía y debe devolver void. La implementación predeterminada de
este método sirve como un receptáculo que no hace nada.
getClass()
Todo objeto en Java conoce su tipo en tiempo de ejecución. El método getClass devuelve un objeto de la clase Class (paquete java.lang), el cual contiene
información acerca del tipo del objeto, como el nombre de su clase (devuelto por el método getName de
Class). Puede aprender más acerca de la clase Class en la documentación de la API en línea, en java.
sun.com/javase/6/docs/api/java/lang/Class.html.
hashCode()
Una tabla de hash es una estructura de datos que relaciona a un objeto,
llamado la clave, con otro objeto, llamado el valor. Cuando inicialmente se inserta un valor en una
tabla de hash, se hace una llamada al método hashCode de la clave. La tabla de hash utiliza el valor de
código de hash devuelto para determinar la ubicación en la que se debe insertar el valor correspondiente.
La tabla de hash también utiliza el código de hash de la clave para localizar el valor correspondiente
de la misma.
notify()
notifyAll()
wait()
Los métodos notify, notifyAll y las tres versiones sobrecargadas de wait están relacionados con el
subprocesamiento múltiple. En versiones recientes de Java, el modelo
de subprocesamiento múltiple ha cambiado en forma considerable, pero estas características se siguen
soportando.
toString()
Este método devuelve una representación String de un objeto. La
implementación predeterminada de este método devuelve el nombre del paquete y el nombre de la clase
del objeto, seguidos por una representación hexadecimal del valor devuelto por el método hashCode del
objeto.