====== Sobrescritura de métodos de la clase Object ====== En Java la clase de la que heredan (directa o indirectamente) todas las clases es la clase ''Object'': todas las clases heredan los métodos de esta ''Object''. Cada vez que una clase hereda un método de una superclase, se tiene la oportunidad de **sobrescribir** el funcionamiento del método. La sobrescritura de métodos heredados se usa para definir el comportamiento específico de un método que tiene un funcionamiento demasiado general en una superclase. Esto se denomina ''Override''. === Etiqueta @Override === Cuando sobrescribimos métodos podemos ayudar al compilador a evaluar si hacemos lo correcto utilizando la etiqueta ''@Override'' en la definición del método. Esto se comenta con más detalle en la sección sobre [[bloque3:herencia#Etiqueta @Override|Herencia de Clases]]. ===== Métodos de la clase Object ===== La clase [[https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html|Object]] tiene una serie de métodos, aunque solo sobrescribiremos los métodos que consideremos necesarios: ^Método^Descripción^ |String **toString**()|Devuelve la representacion en String del objeto| |boolean **equals**(Object obj)|Indica si el objeto actual es igual al parametro **obj**| |Object clone()|Devuelve una copia del objeto. El objeto debe implementar la interface [[https://docs.oracle.com/javase/8/docs/api/java/lang/Cloneable.html|Cloneable]]| |int hashCode|Devuelve el código hash del objeto. Está enfocado en el uso de tablas //Hash// como las provistas por [[https://docs.oracle.com/javase/8/docs/api/java/util/HashMap.html|HashMap]]| |void finalize()|Método llamado por el recolector de basura, cuando no quedan referencias a ese objeto| |Class getClass()|Devuelve la clase del objeto| |void notify()|Despierta un hilo de ejecución que está en estado de espera| |void notifyAll()|Despierta todos los hilos que están en espera| |void wait()| Pone en espera un hilo de ejecución, hasta que se llame a notify() o notifyAll()| |void wait(long time)|Pone en espera la cantidad de tiempo, o hasta notify() o notifyAll()| |void wait(long time, int nanos)|Pone en espera al hilo de ejecución| Dependiendo de la finalidad de nuestra clase nos podría interesar sobrescribir unos métodos u otros. === Impedir la sobrescritura === Todo método declarado como ''final'' en una clase, no puede ser sobrescrito. Esto ocurre también en la clase Object. Los únicos métodos que se pueden sobrescribir son: **toString(), equals(), hashCode(), clone() y finalize()**. ===== Generar métodos desde Eclipse ===== {{ :bloque3:sourcemenueclipse.png?250|}} Los IDEs ofrecen la posibilidad de generar de forma automática algunos métodos de la clase Object. Desde la pestaña ''Source'' del menu, o haciendo clic derecho en el editor de texto -> ''Source'' accedemos al siguiente menu: Pulsando sobre la generación de esos métodos, eclipse nos ayuda a generarlos. Por ejemplo, la implementación del método ''toString()'' devuelve un String utilizando el valor de todos los atributos. Podemos modificarlo si queremos mostrar menos, o dar otro formato. ---- ===== Override: método toString() ===== Tal como se indica en la documentación de la clase [[https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html|Object]], el método ''toString()'' se usa para obtener una "representacion textual" de un objeto. El método toString() está enfocado en la representación de un objeto hacia el usuario. La información que muestra debe ser concisa pero explicativa para que lo entienda una persona. El método de la clase ''Object'' devuelve un String compuesto por el nombre de la clase, una @, y el código ''hash'' en hexadecimal de ese objeto. Cuando nosotros creamos una clase, puede que necesitemos tener un modo textual de representar a los distintos objetos. **Por lo que se recomienda que todas las subclases de Object lo sobrescriban**. Es el __programador que crea la clase quien debe elegir qué información considera oportuna__ para representar al objeto. public class Persona{ private String dni; private String nombre; private String apellido1; private String apellido2; private LocalDate fechaNacimiento; private float altura; private float peso; private String colorOjos; private String complexion; @Override public String toString(){ return dni + " - " + nombre + " " + apellido1 + " " + apellido2; } } La principal ventaja de sobrescribir toString() __es poder mostrar por consola directamente una variable__ de referencia de una clase. Automáticamente se llamará al método toString() de esa clase. Persona persona1 = new Persona(); System.out.println(persona1); // Se ejecuta implicitamente el método toString() ===== Override: método equals() ===== El método equals se usa para saber si un objeto es igual a otro, devolviendo ''true'' o ''false''. Cuando dos objetos pertenecen a distinta clase, es fácil evaluarlo (nunca serán iguales). Pero cuando dos objetos pertenecen a la misma clase, aunque sean objetos distintos, nos podría interesar establecer un criterio para indicar cuando son iguales. Por ejemplo: * Con **dos objetos String distintos**, el método ''equals()'' devuelve ''true'' si contienen la misma cadena de texto. * Con **dos objetos LocalDate distintos**, el método ''equals()'' devuelve ''true'' cuando representan la misma fecha. El método ''equals()'' de la clase ''Object'' indica ''true'' únicamente cuando se trata del mismo objeto creado (ambas variables contienen la dirección del mismo objeto), como se explica en el siguiente ejemplo: Persona persona1 = new Persona(); Persona persona2; //Las dos variables de referencia contienen la misma dirección de memoria //Es decir, apuntan o referencian al mismo objeto persona2 = persona1; //Entonces el método equals heredado de Object persona1.equals(persona2); //Devuelve true //Pero si contienen referencias a objetos distintos persona2 = new Persona(); persona1.equals(persona2); //Devuelve false Aunque establecer un criterio para comparar 2 objetos es bastante sencillo (por ejemplo 2 personas son iguales si tienen el mismo dni), se deben cumplir unas normas. ==== Normas para sobrescribir equals() ==== Se definen unas normas que toda implementación del método [[https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-|equals()]] que se precie, debe cumplir. * **Debe ser reflexivo**; para ''x'' distinto de null, x.equals(x) devuelve ''true''. * **Debe ser simétrico**; para ''x'' e ''y'' distintos de ''null'', x.equals(y) == y.equals(x). * **Debe ser transitivo**; para ''x'', ''y'' y ''z'' distintos de ''null'', si x.equals(y) es true, y y.equals(z) es true, entonces x.equals(z) debe ser true. * **Debe ser consistente**; para ''x'' e ''y'' distintos de ''null'', todas las llamadas a x.equal(y) devuelven siempre el mismo valor, mientras no cambien el valor de los atributos comparados. * Si x es distinto de ''null'', x.equals(null) debe ser ''false''. Atendiendo a esto podemos seguir el siguiente patrón a la hora de sobrescribir este método: public class Persona{ private String dni; private String nombre; private int edad; @Override public boolean equals(Object obj){ if (this == obj){ //Si referencian al mismo objeto return true; } if (obj == null){ //Si lo que recibe es null return false; } if (this.getClass() != obj.getClass()){ //Si no son de la misma clase return false; } Persona other = (Persona) obj; //Si sus valores no son iguales if ( ! ((this.dni.equals(other.dni) && (this.nombre.equals(other.nombre)) && (this.edad == other.edad))){ return false; } return true; //Si no he devuelto false, es que son iguales } } Si puede que nuestros objetos se almacenen el algún tipo de estructura //Hash// debemos sobrescribir el método ''hashCode()'' en concordancia con el método ''equals()''. ---- (c) {{date> %Y}} Fernando Valdeón