133
Extensión de clases

Extensión de clases

  • Upload
    chase

  • View
    50

  • Download
    0

Embed Size (px)

DESCRIPTION

Extensión de clases. Introducción. El conjunto de métodos y campos accesibles desde el exterior de una clase, junto con la descripción de la forma en que se espera que esos miembros se comporten se denomina comúnmente el contrato de la clase. - PowerPoint PPT Presentation

Citation preview

Page 1: Extensión de clases

Extensión de clases

Page 2: Extensión de clases

Introducción El conjunto de métodos y campos

accesibles desde el exterior de una clase, junto con la descripción de la forma en que se espera que esos miembros se comporten se denomina comúnmente el contrato de la clase.

El contrato es lo que el diseñador de la clase ha prometido que la clase va a hacer

Page 3: Extensión de clases

Introducción La extensión de clases proporciona dos

formas de herencia: Herencia de contrato o tipo, por la que una

subclase adquiere el tipo de la superclase y se puede utilizar polimórficamente allí donde se pudiera utilizar la superclase.

Herencia de implementación, por lo que una subclase adquiere la implementación de la superclase en término de sus campos y métodos accesibles.

Page 4: Extensión de clases

Introducción

La extensión de clases puede usarse para múltiples propósitos. El más común es la especialización, donde la clase extendida define su nuevo comportamiento y por tanto se convierte en una versión especializada de su superclase.

Page 5: Extensión de clases

Introducción La extensión de clases puede involucrar

sólo el cambio de la implementación de un método heredado, quizá para hacerlo más eficiente.

Siempre que se extiende una clase, se crea una nueva clase con un contrato ampliado.

Sin embargo, no se cambia la parte del contrato que se hereda de la clase que se extiende

Page 6: Extensión de clases

Introducción Cambiar la forma en la que se implementa el

contrato de la superclase es razonable, pero nunca se debe hacerlo de forma en que se viole el contrato

La capacidad de extender clases está relacionada con los mecanismos de control de acceso para ampliar la noción del contrato que la clase presenta. Una clase puede presentar dos contratos diferentes: uno para los usuarios de la clase y otro para los extensores de la clase, ambos deben diseñarse cuidadosamente

Page 7: Extensión de clases

Introducción Al extender una clase, la herencia de

contrato y la herencia de implementación siempre se producen juntas. Sin embargo, pueden definirse nuevos tipos independientes de implementación usando interfaces.

Se pueden reutilizar implementaciones existentes, sin afectar al tipo, utilizando manualmente la composición y el reenvío.

Page 8: Extensión de clases

Una clase extendida Como ejemplo se muestra una clase de

atributos básica diseñada para almacenar parejas nombre-valor. Los nombres de los atributos son cadenas legibles como “color” o “posición”

Los valores de los atributos están determinadas por el tipo de atributo, por ejemplo, posición puede tener el valor de cadena de texto que represente la dirección de una calle, un conjunto de valores enteros representando longitud y latitud

Page 9: Extensión de clases

Una clase extendida

public class Atrib {private final String nombre;private Object valor=null;public Atrib (String nombre){this.nombre=nombre;}public Atrib(String nombre, Object valor) {this.nombre = nombre;this.valor = valor;}

Page 10: Extensión de clases

Una clase extendida

Un atributo debe tener un nombre, de forma que cada constructor requiere una parámetro de nombre.

El nombre debe ser inmutable (y por tanto se marca como final) ya que puede usarse por ejemplo en una lista enlazada.

Page 11: Extensión de clases

Una clase extendida Los atributos pueden tener cualquier tipo de

valor por lo que dicho valor se almacena en una variable de tipo Object.

El valor puede cambiar en cualquier momento Tanto nombre como valor son miembros private, por lo que puede accederse a ellos mediante los métodos apropiados.

Esto asegura que el contrato de Atrib se cumple siempre y da al diseñador de Atrib la libertad de cambiar en el futuro los detalles de la implementación sin afectar a los clientes de la clase

Page 12: Extensión de clases

Una clase extendida

public String getNombre() {return nombre;}public Object getValor() {return valor;}

Page 13: Extensión de clases

Una clase extendida

public Object setValor(Object nuevoValor){Object valorAnt=valor;valor=nuevoValor;return valorAnt;}public String toString(){return nombre + "='" + valor + “ ";}}

Page 14: Extensión de clases

Una clase extendida Todas las clases vistas hasta ahora son clases

extendidas, aunque no se declaren como tales. Una clase como Atrib que no extiende

explícitamente a otra clase, extiende implícitamente a Object.

Object está en la raíz de la jerarquía de clases y declara métodos que son implementados por todos los objetos, como toString

Las variables de tipo Object pueden referirse a cualquier objeto, sea éste una instancia de una clase o un array

Page 15: Extensión de clases

Una clase extendida La siguiente clase extiende la noción de

atributos de color, que podrían ser cadenas de texto para nombrar o describir colores.

Podría ser nombres como “crudo”, que podrían buscarse en una tabla o bien, valores numéricos que pueden decodificarse para producir una representación del color más eficiente que llamaremos ColorPantalla (que se supone definida en alguna otra parte)

Page 16: Extensión de clases

Una clase extendida La decodificación de una descripción en

un objeto ColorPantalla es lo suficientemente costosa como para desear realizarla una sola vez

Se extiende por tanto la clase Atrib creando una nueva clase AtribColor que tenga un método que obtenga un objeto ColorPantalla decodificado, implementado de tal forma que la decodificación se realice una sola vez

Page 17: Extensión de clases

Una clase extendida

public class AtribColor extends Atrib{private ColorPantalla miColor; //el color decodificadopublic AtribColor (String nombre, Object valor){super(nombre, valor);decodifColor();}public AtribColor(String nombre){this(nombre, "transparente");}

Page 18: Extensión de clases

Una clase extendida

public AtribColor(String nombre, ColorPantalla valor){super(nombre, valor.toString());miColor=valor;}public Object setValor(ColorPantalla nuevoValor){//se hace que setValor de la superclase actúe primerosuper.setValor(nuevoValor.toString());ColorPantalla antValor= miColor;miColor= nuevoValor;return antValor;}public Object setValor(Object nuevoValor){//se hace que setValor de la superclase actúe primeroObject devValor=super.setValor(nuevoValor);decodifColor();return devValor;}

Page 19: Extensión de clases

Una clase extendida

//devuelve el objeto ColorPantalla decodificadopublic ColorPantalla getColor(){return miColor;}//de un valor a ColorPantalla en función de la descripción en getValorprotected void decodifColor(){if(getValor()==null)miColor=null;elsemiColor=new ColorPantalla(getValor());}}

Page 20: Extensión de clases

Una clase extendida

AtribColor hace todo lo que hace Atrib y añade nuevo comportamiento

Object

Atrib

AtribColor

Page 21: Extensión de clases

Una clase extendida La clase extendida AtribColor hace

principalmente tres cosas: Proporciona tres constructores: dos para

reflejar los de su superclase y uno que acepta directamente un objeto ColorPantalla

Modifica y redefine el método setValor de su superclase, para que pueda establecer el objeto de color cuando se cambia el valor

Proporciona un nuevo método getColor que devuelve un valor que es la descripción del color decodificada en un objeto ColorPantalla

Page 22: Extensión de clases

Una clase extendida

Es interesante notar el uso del modificador de acceso protected en el método decodifColor, al marcarlo así puede accederse al mismo en la clase actual o, en una subclase pero, no es visible externamente

Page 23: Extensión de clases

Constructores en clases extendidas

Los objetos de las clases extendidas contienen variables de estado (campos) heredados de la superclase y campos definidos localmente en la clase.

Para construir un objeto de una clase extendida se deben inicializar correctamente ambos conjuntos de campos

Page 24: Extensión de clases

Constructores en clases extendidas El constructor en una clase extendida

puede tratar con campos locales pero sólo la superclase sabe cómo inicializar correctamente su estado, de forma que se cumpla su contrato.

Los constructores de clases extendidas deben delegar la construcción del estado heredado implícitamente o explícitamente invocando a un constructor de la superclase

Page 25: Extensión de clases

Constructores en clases extendidas Un constructor de la clase extendida puede

invocar directamente a uno de los constructores de la superclase usando otra clase de invocación explícita a un constructor: la invocación del constructor de la superclase, que usa la construcción super, Ej.: primer constructor de la clase AtribColor, al que se le pasa el nombre y el valor al correspondiente constructor de 2 argumentos de la superclase. Entonces se invoca a su propio método decodifColor para conseguir que miColor contenga una referencia al objeto ColorPantalla correcto

Page 26: Extensión de clases

Constructores en clases extendidas Puede retrasarse la elección de qué

constructor de la superclase va a utilizarse invocando explícitamente a uno de los constructores propios de la clase, usando this en vez de super, como se ve en el 2º constructor de AtribColor. Se asegura que cada atributo de color tiene un color, sino se proporciona un valor de color proporcionamos un valor por defecto de “transparente”.

Page 27: Extensión de clases

Constructores en clases extendidas Sino se invoca al constructor de la superclase

o a uno de nuestros propios constructores como primera sentencia ejecutable de nuestro propio constructor, se invoca automáticamente al constructor no-arg de la superclase antes de que se ejecute ninguna sentencia del nuevo constructor. Es decir, nuestro constructor se trata como si super() fuese su primera sentencia. Si la superclase no tiene un constructor no-arg, debe invocarse explícitamente a otro constructor.

Page 28: Extensión de clases

Constructores en clases extendidas El 3º constructor de AtribColor permite al

programador crear un nuevo objeto de tipo AtribColor para especificar al propio objeto ColorPantalla. Los 2 primeros constructores deben convertir sus parámetros a objetos ColorPantalla usando el método decodifColor, lo que posiblemente tiene un trabajo adicional. Cuando el programador tiene ya un objeto ColorPantalla para proporcionarle un valor, es conveniente evitar el trabajo adicional de esa conversión. Este es un ejemplo de cómo al proporcionar un constructor se aumenta la eficiencia, pero no se añaden capacidades nuevas.

Page 29: Extensión de clases

Constructores en clases extendidas

En este ejemplo AtribColor tiene constructores con las mismas signaturas que los constructores de la superclase. Esto no es en absoluto necesario, más aún es habitual.

Los constructores no son métodos y no se heredan

Page 30: Extensión de clases

Dependencias de ordenación de constructores

Cuando se crea un objeto, se reserva memoria para todos sus campos, incluyendo aquéllos que se heredan de su superclase. Estos campos se inicializan con valores que dependen de sus tipos respectivos (Ej.: 0 para valores numéricos, null para referencias a objetos)

Page 31: Extensión de clases

Dependencias de ordenación de constructores Después, la construcción tiene 3 fases:

Se invoca al constructor de la superclase Se inicializan los campos usando sus

inicializadores y los bloques de inicialización Se ejecuta el cuerpo del constructor

1º se ejecuta la invocación implícita o explícita al constructor de la superclase.

Page 32: Extensión de clases

Dependencias de ordenación de constructores

Si se usa una invocación explícita a un constructor con this, se sigue la cadena de invocaciones hasta que se encuentra una invocación implícita o explícita a un constructor de la superclase, se invoca entonces al constructor de la superclase.

Page 33: Extensión de clases

Dependencias de ordenación de constructores El constructor de la superclase se ejecuta

usando las mismas 3 fases. Este procedimiento se aplica recursivamente, finalizándose cuando se alcanza el constructor de Object, ya que en este punto no existe ningún constructor de una superclase. Cualquier expresión evaluada como parte de la invocación explícita a un constructor no se puede referir a ningún miembro del objeto actual

Page 34: Extensión de clases

Dependencias de ordenación de constructores

En la segunda etapa todos los inicializadores de los campos y los bloques de inicialización se ejecutan en orden el que han sido declarados. En esta etapa se permiten referencias a otros miembros del objeto actual, suponiendo que hayan sido declarados

Page 35: Extensión de clases

Dependencias de ordenación de constructores Finalmente, se ejecutan las sentencias

reales del cuerpo del constructor. Si ese constructor se invocó explícitamente, tras la finalización de esas sentencias se devuelve el control al constructor que lo invocó y se ejecuta el resto de su cuerpo. Este proceso se repite hasta que se haya ejecutado el cuerpo del constructor especificado como parte de la construcción new

Page 36: Extensión de clases

Herencia y redefinición de miembros

Cuando se extiende una clase pueden añadirse miembros a dicha clase y también pueden redefinirse los existentes

El efecto exacto de redefinir un miembro heredado depende de la clase de miembro

Page 37: Extensión de clases

Redefinición

En la clase AtribColor se redefine y sobrecarga el método setValor

Sobrecargar un método significa proporcionar más de un método (en la misma clase) con el mismo nombre pero con diferente signatura, para distinguirlos

Page 38: Extensión de clases

Redefinición Redefinir un método quiere decir sustituir

la implementación del método de la superclase con uno propio. Las signaturas deben ser idénticas

Sobrecargar un método heredado quiere decir simplemente que hemos añadido un nuevo método con el mismo nombre que un método heredado pero con diferente signatura. Ej. setValor en AtribColor

Page 39: Extensión de clases

Redefinición Redefinir un método significa que se sustituye su

implementación, de forma que cuando se invoca al método sobre un objeto de la subclase, en realidad se invoca a la versión del método de la subclase.

En AtribColor redefinimos el método setValor(Object) de la clase Atrib proporcionando un nuevo método setValor(Object) que utiliza la palabra reservada super para invocar la implementación de la superclase y luego invoca a decodifColor. La referencia super se puede utilizar en invocaciones a métodos para acceder a métodos de la superclase que hayan sido redefinidos en la clase actual

Page 40: Extensión de clases

Redefinición

Cuando se redefinen métodos, la signatura y el tipo de retorno deben ser los mismos que en la superclase. Aunque dos métodos se diferencien sólo en el tipo de retorno, esto es un error y el compilador rechazará esta clase

Page 41: Extensión de clases

Redefinición Los métodos que redefinen a otros poseen sus

propios especificadores de acceso. Una subclase puede modificar el acceso a los métodos de la superclase, pero sólo para hacerlos más accesibles. Un método declarado protected en la superclase puede volverse a declarar de esta forma (lo usual) o se puede declarar public pero no puede declararse private ni tener acceso de paquete. Al hacer un método menos accesible que en la superclase se violaría el contrato de ésta, ya que una instancia de la subclase no podría utilizarse en lugar de una instancia de la superclase

Page 42: Extensión de clases

Redefinición Los métodos que redefinen a otros

pueden también cambiar los modificadores de los otros métodos.

Pueden ser final pero obviamente el que está siendo redefinido no

Un método de instancia no puede tener la misma signatura que un método estático heredado, ni viceversa. Sin embargo, un método redefinido se puede hacer abstract incluso aunque no lo fuera el método de la superclase

Page 43: Extensión de clases

Redefinición

En una subclase puede cambiarse el hecho que un parámetro de un método redefinido sea final, ya que el modificador final de un parámetro no es parte de la signatura del método, sino un detalle de la implementación

Page 44: Extensión de clases

Ocultación de campos Los campos no pueden redefinirse,

sólo pueden ocultarse. Si declaramos un campo en nuestra clase con el mismo nombre de un campo en la superclase, este otro existirá todavía, pero no podrá accederse directamente a él con su nombre simple. Debe usarse super u otra referencia del tipo de nuestra superclase para acceder a ese campo

Page 45: Extensión de clases

Acceso a miembros heredados

Cuando un método accede a un miembro de un objeto que se ha redefinido en una subclase, ¿a qué miembro se referirá el método?, ¿al de la superclase o al de la subclase?. La respuesta depende de la clase de miembro, de su accesibilidad y de cómo nos referimos a él

Page 46: Extensión de clases

Acceso a miembros heredados

Al invocar un método mediante una referencia de objeto, la clase real del objeto gobierna la implementación que se utiliza. Cuando se accede a un campo se utiliza el tipo declarado de la referencia.

Page 47: Extensión de clases

Acceso a miembros heredados

public class SuperMostrar {public String cad="SuperCad";public void mostrar(){System.out.println("Super.mostrar: "+ cad);}}

Page 48: Extensión de clases

Acceso a miembros heredados

public class ExtendMostrar extends SuperMostrar{public String cad= "ExtendCad";public void mostrar(){System.out.println("Extend.mostrar: "+ cad);}public static void main(String []args){ExtendMostrar ext= new ExtendMostrar();SuperMostrar sup= ext;sup.mostrar();ext.mostrar();System.out.println("sup.cad= "+sup.cad);System.out.println("ext.cad= "+ext.cad);}}

Page 49: Extensión de clases

Acceso a miembros heredados

Sólo hay un objeto, pero tenemos dos variables que contienen referencias al mismo. Una variable tiene tipo SuperMostrar (la superclase) y la otra tiene tipo ExtendMostrar (la clase real).

Veamos la salida del programa cuando se ejecuta

Page 50: Extensión de clases

Acceso a miembros heredados

Extend.mostrar: ExtendCadExtend.mostrar: ExtendCadsup.cad= SuperCadext.cad= ExtendCad

Page 51: Extensión de clases

Acceso a miembros heredados En el caso del método mostrar, el

comportamiento es el esperado. La clase real del objeto, no el tipo de la referencia, gobierna la versión del método que se llama. Cuando tenemos un objeto ExtendMostrar, al invocar a mostrar se llama al método de ExtendMostrar, incluso aunque el acceso sea mediante una referencia declarada con el tipo SuperMostrar. Esto sucede siempre que mostrar se invoca externamente o internamente dentro de otro método de ExtendMostrar o SuperMostrar

Page 52: Extensión de clases

Acceso a miembros heredados En el caso del campo cad, el tipo

de referencia, no la clase real del objeto, determina a qué campo de la clase se accede. De hecho, cada objeto ExtendMostrar tiene dos campos String, ambos llamados cad, uno de los cuales está oculto por el propio campo diferente de ExtendMostrar llamado cad:

Page 53: Extensión de clases

Acceso a miembros heredados

Object

SuperMostrar cad= “SuperCad”

ExtendMostrar cad=”ExtendCad”

Page 54: Extensión de clases

Acceso a miembros heredados El campo al que se accede se determina en

tiempo de compilación basándose en el tipo de la referencia, utilizado en el acceso

Dentro de un método como mostrar, una referencia a un campo siempre se refiere al campo declarado en la clase en la que se declara el método, o bien a un campo heredado si no hay declaración en esa clase. Por tanto en SuperMostrar.mostrar, la referencia a cad se refiere a SuperMostrar.cad mientras que en ExtendMostrar.mostrar la referencia a cad se refiere a ExtendMostrar.cad

Page 55: Extensión de clases

Acceso a miembros heredados La redefinición de métodos posibilita

la extensión del código existente, reutilizándolo con objetos de funcionalidad ampliada y especializada no previstos por el creador del código original. Pero en lo que se refiere a los campos, es difícil imaginar casos en los que su ocultación sea una característica útil

Page 56: Extensión de clases

Acceso a miembros heredados Si un método existente tuviera un parámetro de tipo

SuperMostrar y accediera a cad con esa referencia de objeto, se obtendría siempre SuperMostrar.cad, incluso aunque el método manejara realmente un objeto de tipo ExtendMostrar.

Si las clases se diseñaran para utilizar un método en vez de un campo para acceder a la cadena de texto, el método redefinido se invocaría en ese caso y se podría devolver ExtendMostrar.cad. Este comportamiento de ocultación es frecuentemente otra razón para que se prefiera definir clases con datos privados a los que se accede sólo mediante métodos que se redefinen y no se ocultan

Page 57: Extensión de clases

Accesibilidad y redefinición Un método puede ser redefinido sólo si es

accesible. Si un método no es accesible no puede heredarse y sino se hereda no puede redefinirse. Por ejemplo, un método private no es accesible fuera de su propia clase. Si una subclase definiera un método que por coincidencia tuviera la misma signatura y tipo de retorno que el método privado de la superclase, los métodos no estarían relacionados en absoluto y, el método de subclase no redefiniría al método privado de la superclase

Page 58: Extensión de clases

Accesibilidad y redefinición En pocas palabras, las invocaciones a

métodos privados siempre invocan a la implementación del método declarada en la clase actual.

Cuando un método es inaccesible debido a que la superclase y la subclase están en diferentes paquetes, las cosas son más complicadas.

Page 59: Extensión de clases

Ocultación de miembros estáticos Los miembros estáticos dentro de una clase no

pueden redefinirse. Siempre están ocultos sean campos o métodos. Sin embargo, el hecho de que estén ocultos tiene poco efecto. Un método o campo estático debe ser accedido siempre mediante el nombre de la clase en donde se declara, por lo que el hecho de que quede oculto por la declaración en una subclase tiene poca importancia.

Si se usa una referencia para acceder a un miembro estático, como con campos de instancia, se accede siempre basándose en el tipo declarado de la referencia, no en el tipo del objeto al que se referencia

Page 60: Extensión de clases

La palabra reservada super La palabra clave super puede utilizarse

con todos los métodos no estáticos de una clase. En acceso a campos e invocación de métodos, super actúa como una referencia al objeto actual como una instancia de su superclase.

El uso de super es el único caso en el que el tipo de la referencia gobierna la selección de la implementación del método que se utiliza.

Page 61: Extensión de clases

La palabra reservada super

Una invocación.método siempre utiliza la implementación de método que utilizaría la superclase.

No utiliza ninguna implementación redefinida de este método, descendiendo en la jerarquía de clases

Page 62: Extensión de clases

Ejemplo

public class Ess {//devuelve el nombre de la claseprotected String nm(){return "Ess";}

}

Page 63: Extensión de clases

Ejemplo

public class Mas extends Ess{protected String nm(){return "Mas";}protected void imprimeNM(){Ess sref= (Ess)this;System.out.println("this.nm()= "+this.nm());System.out.println("sref.nm()= "+sref.nm());System.out.println("super.nm()= "+super.nm());}

}

Page 64: Extensión de clases

Ejemplo

Aunque sref y super se refieren al mismo objeto usando el tipo Ess, sólo super ignorará la clase real del objeto usando la implementación de la superclase de nm. La referencia sref actuará de la misma forma que this, seleccionando una implementación de nm basada en la clase real del objeto

Page 65: Extensión de clases

Ejemplo

this.nm()= Massref.nm()= Massuper.nm()= Ess

Page 66: Extensión de clases

Compatibilidad y conversión de tipos

El lenguaje Java es fuertemente tipado, lo que significa que en la mayor parte de los casos comprueba la compatibilidad de tipos en tiempo de compilación. Evita las asignaciones incompatibles prohibiendo cualquier cosa cuestionable

Page 67: Extensión de clases

Compatibilidad Cuando se asigna el valor de una

expresión a una variable, como parte de un inicializador, de una sentencia de asignación o, implícitamente cuando se asigna un parámetro de un método, el tipo de la expresión debe ser compatible con el tipo de la variable.

En el caso de tipos de referencia esto significa que el tipo de la expresión debe ser el mismo que el tipo declarado de la variable o bien un subtipo.

Page 68: Extensión de clases

Compatibilidad Ejemplo: cualquier método que espera un

objeto Atrib como parámetro aceptará un objeto AtribColor, ya que es un subtipo de Atrib. Esto se llama, compatibilidad de asignaciones. Pero lo contrario no es cierto. No se puede asignar un objeto Atrib a una variable de tipo AtribColor, ni pasar un objeto Atrib como parámetro cuando se espera un objeto de tipo AtribColor

Page 69: Extensión de clases

Compatibilidad La misma regla se aplica a la expresión

usada en un sentencia return de un método. El tipo de la expresión debe ser compatible desde el punto de vista de la asignación con el tipo de retorno declarado para el método

La referencia al objeto null es un caso especial que es compatible con todos los tipos de referencia, incluyendo los arrays. Una referencia a una variable de cualquier tipo se puede asignar siempre a null

Page 70: Extensión de clases

Compatibilidad Los tipos que ascienden en la jerarquía de tipos se dice

que son más amplios o menos específicos que los tipos que descienden en la jerarquía

Los tipos inferiores se dice que son menos amplios o más específicos que sus correspondientes supertipos. Cuando se espera un supertipo y se proporciona un subtipo, tiene lugar una conversión de ampliación. Esta conversión hace que el objeto del subtipo sea tratado como una instancia del supertipo y se pueda comprobar en tiempo de compilación. No se requiere ninguna acción por parte del programador en una conversión de ampliación. Al ir en el otro sentido, es decir, al tomar una referencia a un supertipo y convertirla en una referencia a un subtipo, tiene lugar una conversión de restricción. La conversión de restricción se debe indicar expresamente mediante el operador de conversión de tipo (cast).

Page 71: Extensión de clases

Conversión explícita de tipos Se puede usar un operador de conversión

de tipo para indicar al compilador que una expresión se debe tratar como si tuviese el tipo especificado por el operador de conversión. El resultado puede ser de un tipo más amplio o menos amplio, aunque generalmente estos operadores se usan en conversiones de restricción. Un operador de conversión de tipo consiste en un nombre de tipo entre () aplicado a una expresión.

Page 72: Extensión de clases

Conversión explícita de tipos En el ejemplo anterior se usa un operador de

ampliación de tipo en el método imprimeNM para convertir el tipo de this en el tipo de su superclase: Ess sref= (Ess)this;

Este operador de conversión de tipo no es necesario, pero permite enfatizar que lo que realmente deseamos es que ese objeto sea tratado como instancia de su superclase. Si intentamos asignar sref a una referencia de tipo Mas, menos amplio, es necesaria una conversión de tipo explícita:Mas mref= (Mas)sref;

Incluso aunque conozcamos que el objeto referido es del tipo correcto, el compilador necesita una conversión explícita de tipo.

Page 73: Extensión de clases

Conversión explícita de tipos Las conversiones de ampliación se conocen también como

conversiones ascendentes, ya que convierten un tipo en otro de un nivel superior de la jerarquía de tipos. Son también unas conversiones seguras, ya que siempre son válidas. Las conversiones de restricción se llaman también conversiones descendentes ya que convierten un tipo en otro de nivel inferior en la jerarquía. Son también conversiones inseguras, ya que pueden no ser válidas

Cuando se requiere realizar una conversión de restricción mediante un operador de conversión de tipo, el compilador no supone que la conversión es correcta. Si el compilador puede decidir que la conversión es incorrecta puede ocurrir un error en tiempo de compilación. Si el compilador no puede decidir si la conversión es correcta en tiempo de compilación, se realizará una comprobación en tiempo de ejecución. Si esta comprobación falla debido a que la conversión es incorrecta, se lanza una excepción ClassCastException

Page 74: Extensión de clases

Comprobación de tipos Se puede comprobar la clase de un objeto usando

el operador instanceof, que produce true si la expresión de la izquierda es compatible desde el punto de vista de la asignación con el nombre de tipo de su derecha y false en caso contrario. Hay que tener en cuenta que como null no es una instancia de ningún tipo, la aplicación de instanceof a null siempre produce un resultado de false. Se puede usar instanceof para realizar una conversión descendente de forma segura, y asegurar que no se lanzará una excepción.if (sref instanceof Mas)

mref = (Mas)sref;

Page 75: Extensión de clases

Comprobación de tipos Nótese que el operador de conversión de

tipo debe usarse todavía, para convencer al compilador que realmente deseamos usar el objeto como una instancia de la subclase

La comprobación de tipos con instanceof es particularmente útil cuando un método no requiere un objeto de un tipo más extendido, pero al pasarle ese objeto puede hacer uso de la funcionalidad extendida.

Page 76: Extensión de clases

Ejemplo

/*un método ordenar podría aceptar como parámetro * un tipo Lista genérico, pero si realmente recibe un * tipo ListaOrdenada no tendría que hacer nada */public static void ordenar(Lista lista){if (lista instanceof ListaOrdenada)return;//sino, ordenar la lista}

Page 77: Extensión de clases

Lo que significa realmente protected Que un miembro de una clase sea protected significa que puede ser accedido por clases que extiendan a la clase actual.

De forma más concreta, además de ser accesible dentro de la propia clase y dentro del mismo paquete, un miembro protegido también puede ser accedido desde otra clase a través de referencias a objetos que sean al menos del mismo tipo que la clase (es decir, referencias del tipo de la clase o de uno de sus subtipos).

Page 78: Extensión de clases

Ejemplo Consideremos la implementación como

lista enlazada de una cola, la clase ColaMonoEnlace, con métodos añadir y quitar, para almacenar un objeto en el final de la cola y quitar el objeto de la cabecera de la cola, respectivamente. Los nodos de la cola están formados por Celdas que tienen una referencia a la siguiente celda de la cola y una referencia al objeto almacenado en la celda actual

Page 79: Extensión de clases

Ejemplo

public class Celda {private Celda siguiente;private Object elemento;public Celda(Object elemento){this.elemento=elemento;}public Celda(Celda siguiente, Object elemento) {this.siguiente = siguiente;this.elemento = elemento;}public Celda getSiguiente() {return siguiente;}public void setSiguiente(Celda siguiente) {this.siguiente = siguiente;}public Object getElemento() {return elemento;}public void setElemento(Object elemento) {this.elemento = elemento;}}

Page 80: Extensión de clases

Ejemplo

Una cola consiste entonces en una referencia a las celdas de la cabecera y del final, y la implementación de añadir y quitar:public class ColoMonoEnlace {

protected Celda cabecera;protected Celda finali;public void añadir (Objeto item){//}public Object quitar(){//}}

Page 81: Extensión de clases

protected

Hacemos que las referencias cabecera y finali sean protected, de forma que las clases extendidas puedan manejar directamente las celdas enlazadas en vez de usar añadir y quitar, lo que podrá requerir quitar y poner los elementos cada vez

Page 82: Extensión de clases

protected Un grupo decide que necesita una cola con prioridades,

de forma que los elementos se almacenen en la cola en un orden específico en vez de insertarse siempre en el final. Por tanto define una clase ColaConPrioridades, en otro paquete, que extiende a ColaMonoEnlace y redefine añadir para insertar el objeto en el lugar correcto. La implementación de añadir en la clase ColaConPrioridades puede acceder a los campos cabecera y finali heredados de ColaMonoEnlace ya que el código está en una subclase de ColaMonoEnlace y el tipo de la referencia al objeto usada (this) es el mismo que el de la subclase, ColaConPrioridades, por lo que el acceso a los miembros protected está permitido. Esto es lo que podría esperarse.

Page 83: Extensión de clases

protected El grupo que diseña la cola con

prioridades necesita una característica adicional. Desea poder fusionar dos colas con prioridades en una sola. En una operación de fusión la cola destino contiene los elementos de ambas colas, y la otra cola con la que se realiza la fusión queda vacía. La operación fusionar podría empezar así:

Page 84: Extensión de clases

protected

public void fusionar (ColaConPrioridades q){Celda primero= q.cabecera;//....}

Page 85: Extensión de clases

protected No estamos accediendo al miembro protected

del objeto actual, sino al miembro protected de un objeto pasado como parámetro. Esto está permitido ya que la clase que intenta el acceso es ColaConPrioridades y el tipo de la referencia q es también ColaConPrioridades. Si q fuese una subclase de ColaConPrioridades esto sería todavía válido

Posteriormente el grupo determina que hay un nuevo requerimiento: desea poder fundir una ColoMonoEnlace con una ColaConPrioridades. Por tanto define una versión sobrecargada de fusionar que empieza así:

Page 86: Extensión de clases

protected

public void fusionar (ColaMonoEnlace q){Celda primero=q.cabecera;//...}

Page 87: Extensión de clases

protected Pero este código no compila. El problema que aparece es que la clase que

intenta acceder al miembro protected es ColaConPrioridades mientras que el tipo de la referencia del objeto que está siendo accedido es ColaMonoEnlace. Como ColaMonoEnlace no es la misma clase ni una subclase de ColaConPrioridades, el acceso no está permitido. Aunque cada ColaConPrioridades es una ColaMonoEnlace, no todos los objetos ColaMonoEnlace son ColaConPrioridades

Page 88: Extensión de clases

protected El razonamiento que justifica las restricciones

es: cada subclase hereda el contrato de su superclase y expande este contrato de alguna forma. Supongamos que una subclase, como parte del contrato expandido, pone restricciones en los valores de miembros protegidos de la superclase.

Si una subclase diferente pudiese acceder a los miembros protegidos de objetos de la primera subclase, podría manejarlos de forma que violase el contrato de la primera subclase, lo que no es permisible.

Page 89: Extensión de clases

protected Los miembros static protegidos pueden

ser accedidos por cualquier clase extendida. Si cabecera fuese un campo estático, cualquier método (estático o no) de ColaConPrioridades podría acceder al mismo. Esto se permite ya que una subclase no puede modificar el contrato de sus miembros estáticos, y sólo puede ocultarlos, no redefinirlos, por lo que no hay peligro de que otra clase viole el contrato.

Page 90: Extensión de clases

protected Los miembros declarados como protected están

también disponibles para cualquier código dentro del paquete de la clase. Si estas diferentes clases de colas estuviesen en el mismo paquete, podrían acceder cada una de ellas a los campos cabecera y finali de las otras, como podría también cualquier tipo no relacionado del paquete. Las clases del mismo paquete se supone que son de confianza y no violarán entre sí sus contratos.

En la lista “privado, paquete, protegido, público” cada nivel de acceso amplía las clases de código para las que el miembro es accesible

Page 91: Extensión de clases

Marcado de clases y métodos como final Marcar un método como final significa

que ninguna clase extendida puede redefinir el método para cambiar su comportamiento. En otras palabras, es la versión final de ese método. También pueden marcarse como final clases completas:

final class NoSeExtiende{//...}

Page 92: Extensión de clases

Marcado de clases y métodos como final Una clase que se marca como final no

puede extenderse por otra clase y todos los métodos de una clase final son efectivamente final

Las clases y métodos finales pueden mejorar la seguridad. Si una clase es final nadie puede declarar una clase que la extienda, y por tanto, nadie puede violar su contrato. Si un método es final podemos fiarnos de sus detalles de implementación (a menos, por supuesto, que invoque a métodos no finales).

Page 93: Extensión de clases

Marcado de clases y métodos como final Por ejemplo podemos usar final en un

método denominado validarContraseña para asegurarnos de que hace lo que dice que hace, en vez de ser redefinido para devolver siempre true. O podemos marcar como final la clase que contiene al método de forma que nunca se pueda extender para que se confunda la implementación de validarContraseña

Page 94: Extensión de clases

Marcado de clases y métodos como final Marcar un método o una clase como final es una

seria restricción en el uso de una clase. Si hacemos que un método sea final debemos pretender realmente que su comportamiento quede completamente fijo. Estamos restringiendo la flexibilidad de nuestra clase para otros programadores que podrían desear usarla como base para añadir funcionalidad a su código. Al marcar una clase completa se evita que cualquiera pueda extender nuestra clase, limitando así su utilidad para otros. Si marcamos algo como final debemos asegurarnos que deseamos crear estas restricciones

Page 95: Extensión de clases

Marcado de clases y métodos como final En muchos casos, podemos conseguir la

seguridad que buscamos al marcar una clase como final dejando que la clase sea extensible y marcando cada método de la clase como final. De esta forma, podemos fiarnos del comportamiento de esos métodos permitiendo no obstante extensiones que puedan añadir funcionalidad sin redefinir estos métodos. Por supuesto, los campos que son fiables para los métodos final deberían ser final o private. De lo contrario, una clase extendida podría cambiar el comportamiento cambiando esos campos.

Page 96: Extensión de clases

Marcado de clases y métodos como final Otra modificación de final es que

simplifica las optimizaciones. Cuando se invoca a un método no final, el sistema en tiempo de ejecución determina la clase real del objeto, asocia la invocación del método con la implementación correcta del método para este tipo, e invoca después a la implementación.

Page 97: Extensión de clases

Marcado de clases y métodos como final Pero, por ejemplo, si el método getNombre fuera final en la clase Atrib y tuviésemos una referencia a un objeto de tipo Atrib o de un tipo extendido, podría ser posible simplificar los pasos necesarios para invocar al método. En el caso más simple como en getNombre, una invocación se puede sustituir con el cuerpo real del método. Este mecanismo se conoce como inlining (inclusión de líneas).

Page 98: Extensión de clases

Marcado de clases y métodos como final

Esto hace que las 2 siguientes sentencias se comporten de forma equivalente:

System.out.println( "id= " + rosa.nombre);

System.out.println( "id= " + rosa.getNombre());

Page 99: Extensión de clases

Marcado de clases y métodos como final Aunque las dos sentencias son iguales de

eficientes, el método getNombre permite que el campo nombre sea de sólo lectura y nos da los beneficios de la abstracción, permitiéndonos cambiar la implementación

Se pueden aplicar las mismas optimizaciones a métodos privados y estáticos, debido a que tampoco pueden ser redefinidos

Page 100: Extensión de clases

Marcado de clases y métodos como final Algunas comprobaciones de tipos resultan más

rápidos con clases final. De hecho, muchas comprobaciones de tipos se convierten en comprobaciones en tiempo de compilación y, los errores pueden capturarse antes. Si el compilador encuentra una referencia a una clase final, sabe que el objeto referido es exactamente de ese tipo. Se conoce la jerarquía de clases completa para esta clase, por lo que el compilador puede comprobar si cualquier uso es válido o inválido. Con una referencia no final, algunas comprobaciones sólo se pueden realizar en tiempo de ejecución

Page 101: Extensión de clases

Métodos y clases abstractos Un concepto extremadamente útil de la

programación orientada a objetos es el concepto de clase abstracta. Utilizando clases abstractas podemos declarar clases que definen sólo parte de una implementación, dejando a las clases extendidas la tarea de proporcionar las implementaciones específicas de algunos métodos o, de todos. El opuesto de abstracto es concreto. Una clase que tiene sólo métodos concretos, incluyendo implementaciones de cualquier método abstracto heredado de superclases, es un clase concreta.

Page 102: Extensión de clases

Métodos y clases abstractos Las clases abstractas son útiles cuando

parte del comportamiento está definido para la mayoría o todos los objetos de un tipo dado, pero algo del comportamiento sólo tiene sentido para clases particulares y no para una superclase general. Una clase así se se declara como abstract, y los métodos no implementados en esa clase se marcan también como abstract

Page 103: Extensión de clases

Métodos y clases abstractos

public abstract class Figura {

public abstract double area();

public boolean esMenorQue(Figura obj){

if(this.area()<obj.area())

return true;

else return false;

}

}

Page 104: Extensión de clases

Métodos y clases abstractos

Una clase con métodos abstract se debe declarar como abstract. Esta redundancia ayuda al lector a ver rápidamente que la clase es abstract sin recorrerla para ver si algún método de la clase se declara como abstract

Page 105: Extensión de clases

Métodos y clases abstractos

En el ejemplo, el método área() se debe implementar en cada subclase que no sea a su vez abstract, esto es debido a que no existe implementación en esta clase, sólo hay una declaración

Page 106: Extensión de clases

Métodos y clases abstractos

public class Circulo extends Figura {

private double radio;

public Circulo(double radio) {

super();

this.radio = radio;}

public double getRadio() {

return radio;

}

public double area() {

return Math.PI*radio*radio;

}}

Page 107: Extensión de clases

Métodos y clases abstractos

public class Test1 {

public static void main(String[] args) {

Circulo a= new Circulo(1);

Circulo b=new Circulo(2);

if(a.esMenorQue(b))

System.out.println("El círculo de radio "+a.getRadio()+" tiene menor área que el círculo de radio "+b.getRadio());

else

System.out.println("El círculo de radio "+b.getRadio()+" tiene menor área que el círculo de radio "+a.getRadio());

}}

Page 108: Extensión de clases

Métodos y clases abstractos Cualquier clase puede redefinir métodos de

su superclase declarándolos abstract en ese punto del árbol de tipos. Esta técnica es útil, por ejemplo, cuando la implementación por defecto de una clase es inválida para una parte de la jerarquía de clases

No se puede crear un objeto de la clase abstract ya que no habría implementación válida para algunos métodos que podrían ser invocados (si se pueden crear referencias a objetos de clases que la extiendan)

Page 109: Extensión de clases

Extensión de clases: ¿cuándo y como? La posibilidad de escribir clases

extendidas proporciona una gran parte de los beneficios de la programación orientada a objetos. Cuando se extiende una clase para añadir una nueva funcionalidad, se crea lo que comúnmente se denomina relación EsUn. Es decir, la extensión crea una nueva clase de objeto que “es una” variante de la clase original. La relación EsUn es muy diferente de la relación TieneUn, en la que un objeto utiliza a otro objeto para almacenar estado o realizar tareas (“tiene una” referencia al otro objeto)

Page 110: Extensión de clases

Extensión de clases: cuándo y como Ejemplo: Una clase Punto que representa

un punto del plano cartesiano. Se puede extender Punto para crear, por ejemplo, una clase Pixel que represente un punto de color en una pantalla. Un Pixel EsUn Punto, es decir, cualquier cosa que sea verdadera referida a un simple Punto será también verdad para un Pixel. La clase Pixel podría añadir mecanismos para representar el color de un pixel, por ejemplo.

Page 111: Extensión de clases

Extensión de clases: cuándo y como Por otra parte, un Circulo no es un Punto, aunque se pueda describir mediante un Punto y un radio, un Punto tiene usos que puede no tener un Circulo. Por ejemplo, si tuviésemos un método para situar el centro de un rectángulo en un Punto concreto ¿tendría sentido pasárselo a un Circulo? Un Circulo TieneUn Punto pero NoEsUn Punto, por tanto no debería ser una subclase de Punto

Page 112: Extensión de clases

Extensión de clases: cuándo y como El planteamiento de las relaciones EsUn y

TieneUn correctas es sutil y potencialmente crítico. Por ejemplo, una forma común y obvia de diseñar una base de datos de empleados utilizando herramientas orientadas a objetos es usar una clase Empleado que tenga las propiedades de todas las personas (como nombre y número de Empleado) y extenderla para obtener clases para algunos tipos particulares de empleados como Director, Ingeniero y Bibliotecario

Page 113: Extensión de clases

Extensión de clases: cuándo y como Este diseño falla en situaciones reales, en

las que una persona puede actuar desempeñando más de una función. Por ejemplo, un Ingeniero podría estar actuando como Director de un grupo y debería aparecer en sus dos papeles.

Un diseño más flexible sería crear una clase Función y extenderla creando clases de funciones como Director. Cambiaríamos así el diseño de la clase Empleado para que tuviese un conjunto de objetos Funcion.

Page 114: Extensión de clases

Extensión de clases: cuándo y como

De este modo una persona podría estar asociada con un conjunto de funciones cambiantes en la organización. Hemos pasado de decir que un director EsUn Empleado a decir que un Director EsUna Función y que un Empleado puede TenerUna Función de Director, así como otras funciones.

Si se realiza la elección inicial incorrecta, los cambios posteriores en el sistema pueden ser complicados de realizar, ya que podrían requerir cambios importantes en el código. Por ejemplo, los métodos del diseño de la primera base de datos de empleados se basarían sin duda en que un objeto Director se puede usar como un Empleado. Esto ya no sería cierto si tuviésemos que cambiar a un diseño basado en funciones, y todo el código original podría ser inservible

Page 115: Extensión de clases

Diseño de una clase para ser extendida La clase Atrib es un ejemplo de una clase

bien diseñada. Los campos de la clase son private y accesibles únicamente mediante métodos de acceso, lo que evita que sean modificados en forma contraria al contrato de la clase. La clase Atrib presenta una interfaz limpia para sus usuarios y al mismo tiempo se desacopla de otras clases, de forma que permite que su propia implementación cambie en un futuro

Page 116: Extensión de clases

Diseño de una clase para ser extendida

Dado que AtribColor extiende a Atrib ¿Deberíamos modificar el diseño de Atrib para hacerla más adecuada para su extensión? ¿Deberían haber sido protected los campos nombre y valor, en vez de private, de forma que la subclase pudiera acceder a ellos directamente?

Page 117: Extensión de clases

Diseño de una clase para ser extendida

Estas decisiones requieren una consideración y meditación cuidadosa sobre sus beneficios y consecuencias. Hacer que los campos de Atrib fuesen protegidos no daría ningún beneficio a la subclase, ya que todas las acciones que se fueran a realizar sobre esos campos se podrían hacer mediante los métodos public que proporciona Atrib. Por otra parte hacer que estos campos fuesen protegidos impediría futuras modificaciones de la implementación de Atrib, ya que las subclases podrían depender de la existencia y el tipo de esos campos, así como del acceso directo a ellos. Por tanto, en este caso, el diseño actual de Atrib es adecuado para su extensión así como para su uso general

Page 118: Extensión de clases

Diseño de una clase para ser extendida En la implementación de una cola mediante

una lista enlazada, ColaMonoEnlace, los campos cabecera y finali fueron protected. En ese caso había un gran beneficio en prestaciones, al hacer que la subclase pudiese acceder a las celdas de la lista enlazada directamente. No sería práctico implementar la redefinición de añadir en ColaConPrioridades si las únicas herramientas a usar fuesen los métodos añadir y quitar originales.

Page 119: Extensión de clases

Diseño de una clase para ser extendida La naturaleza de bajo nivel de la clase ColaMonoEnlace significa también que no nos importa demasiado atarnos a detalles de implementación. Después de todo, es una implementación con una lista enlazada de una cola, y realmente no quedan muchas opciones para cambios. Si hubiésemos escrito una clase de colas más general, que usara una implementación de una lista enlazada, la historia hubiese sido diferente

Page 120: Extensión de clases

Diseño de una clase para ser extendida Una clase no final tiene dos interfaces.

La interfaz pública es para los programadores que usan nuestra clase. La interfaz protegida es para los programadores que extienden nuestra clase. No es conveniente hacer a la ligera que campos de nuestras clases sean protegidos. Ambas interfaces son contratos reales, y ambas deben ser diseñadas cuidadosamente

Page 121: Extensión de clases

Herencia simple frente a herencia múltiple Una clase nueva puede extender sólo a

una superclase, modelo conocido como herencia simple. La extensión de una clase significa que la nueva clase no sólo hereda el contrato de su superclase sino también la implementación de su superclase. Algunos lenguajes orientados a objetos emplea herencia múltiple en la que la nueva clase puede tener dos o más superclases

Page 122: Extensión de clases

Herencia simple frente a herencia múltiple La herencia múltiple es útil cuando

una nueva clase desea combinar múltiples contratos y heredar alguna de las implementaciones de esos contratos, o todas. Pero si hay más de una superclase, surgen problemas cuando el comportamiento de una superclase se hereda de dos formas. Supongamos por un momento el siguiente árbol de tipos:

Page 123: Extensión de clases

Herencia simple frente a herencia múltiple

W

YX

Z

Page 124: Extensión de clases

Herencia simple frente a herencia múltiple

Esto se conoce comúnmente como herencia en diamante, y no hay nada erróneo en ello. Muchos diseños legítimos muestran esta estructura. Los problemas aparecen cuando la implementación de W almacena algún estado. Si por ejemplo, la clase W tuviese un campo público llamado algo, y tuviésemos una referencia a un objeto de tipo Z llamada zref ¿a qué se referiría zref.algo? Podría referirse a la copia de X de algo, o podría referirse a la copia de Y de algo o X e Y podrían compartir una única copia de algo debido a que Z es realmente sólo un W, incluso aunque Z es a la vez X e Y

Page 125: Extensión de clases

Herencia simple frente a herencia múltiple

La resolución de estos aspectos no es trivial y complica el diseño y el uso de la jerarquía de clases. Para evitar estos problemas, el lenguaje de programación Java utiliza el modelo de herencia simple de programación orientada a objetos.

Page 126: Extensión de clases

Herencia simple frente a herencia múltiple La herencia simple imposibilita la realización

de algunos diseños útiles y correctos. Los problemas de la herencia múltiple surgen de la herencia múltiple de la implementación, pero en muchos casos la herencia múltiple se utiliza para heredar algunos contratos abstractos y posiblemente una implementación concreta. Proporcionar un medio de heredar un contrato abstracto sin heredar una implementación, permite tener los beneficios de la herencia múltiple, sin que aparezcan los problemas de la herencia de implementación. La herencia de un contrato abstracto se denomina herencia de interfaz. El lenguaje de programación Java admite este tipo de herencia porque permite declarar un tipo interface

Page 127: Extensión de clases

La clase Object Es la raíz de la jerarquía de clases.

Todas las clases extienden directa o indirectamente de ella y por tanto una variable de tipo Object puede referirse a cualquier objeto, sea éste la instancia de una clase o un array. Por ejemplo: la clase Atrib puede almacenar un atributo de cualquier tipo por lo que se declara de tipo Object.

Page 128: Extensión de clases

La clase Object Una clase así no puede almacenar tipos

primitivos (ejemplo: int) pero pueden hacerse objetos que contengan valores de estos tipos si es necesario, usando clases de envoltura (Por ejemplo: Integer)

La clase Object define algunos métodos que son heredados por todos los objetos. Ejemplo: public String toString() que devuelve una implementación de cadena de texto del objeto

Page 129: Extensión de clases

La clase Object El método toString se invoca

implícitamente siempre que se utiliza una referencia a un objeto como un operando del operador + en una expresión de concatenación de cadena de textos. La versión de este método en Object construye una cadena que contiene el nombre de la clase del objeto un carácter @ y una representación hexadecimal del código hash de la instancia

Page 130: Extensión de clases

La clase Object public final Class getClass().getName() devuelve el nombre de la clase de un objeto, se determina en tiempo de ejecución

public boolean equals (Object obj) Compara el objeto receptor con el referido por obj para ver si son iguales, devolviendo true si tienen el mismo valor y false en caso contrario

Page 131: Extensión de clases

La clase Object

Si deseamos determinar si 2 referencias se refieren al mismo objeto, podemos compararlas usando == y !=. El método equals pregunta por la igualdad de valores. La implementación por defecto de equals en Object supone que un objeto sólo es igual a sí mismo, comprobando si this==obj

Page 132: Extensión de clases

La clase Object El método equals se puede redefinir si se desea

proporcionar una noción de igualdad diferente de la implementación por defecto que se proporciona en la clase Object. La opción por defecto es que 2 objetos diferentes no son equal.

El término identidad se usa para indicar igualdad de referencias: si 2 referencias son idénticas, la operación == entre ellas devolverá true. El término equivalencia se usa para indicar igualdad de valores (objetos que pueden ser o no idénticos, pero para los que equals devuelve true). Por tanto, puede decirse que en la implementación por defecto de equals la equivalencia es lo mismo que la identidad.

Page 133: Extensión de clases

La clase Object

Una clase que defina una noción más amplia de igualdad puede tener objetos que no sean idénticos, pero que sean equivalentes, si redefine equals para que devuelva true basándose en los estados de los objetos en vez de sus identidades