Sie sind auf Seite 1von 11

FUNDAMENTOS DE PROGRAMACIN

Versin: 0.0.5

Tema 3. Diseo de Tipos I


Autor: Miguel Toro Bonilla
Revisin: Jos C. Riquelme
Adaptacin a FP: Rafael Romero
Tiempo estimado: 4 horas
1.

Esquema de diseo de tipos ....................................................................................................................... 1

2.

El tipo Object ............................................................................................................................................... 2

3.

El tipo Comparable...................................................................................................................................... 5

4.

El tipo Comparator ...................................................................................................................................... 7

5.

Ordenacin de arrays con la clase de utilidad Arrays. .............................................................................. 9

6.

Ejercicios.................................................................................................................................................... 10

1. Esquema de diseo de tipos


En este captulo vamos a ampliar el esquema de diseo de tipos que vimos en el Tema 1. Este esquema ser
ampliado en temas posteriores. Es decir, iterativamente vamos a ir completando nuestro esquema de diseo
conforme vayamos avanzando en los temas de la asignatura.
Un buen diseo de tipos es bsico para que los programas sean comprensibles y fciles de mantener.
Veamos algunas pautas para este diseo y algunos ejemplos que puedan servir de gua.
En el Tema 1, vimos que debamos fijarnos en las propiedades del tipo, en el tipo de cada una, en si son
consultables y modificables, o si son bsicas o derivadas. Adems de esto, al disear un tipo nuevo debemos
partir de los ya existentes. Es necesario decidir a qu otros tipos extender. En este captulo nos vamos a
centrar en los tipos Object y Comparable, y aunque se pueden extender otros tipos, como hemos visto en el
Tema 2, la extensin de los mismos se ver con ms detalle en temas posteriores.
La primera decisin a tomar es qu tipos debe extender el tipo diseado o qu otros tipos puede usar. Para
ello es conveniente disponer de un catlogo de tipos tiles para disear otros tipos. Teniendo esto en
cuenta, nuestra plantilla para el diseo de un tipo, de momento, queda de la siguiente forma:
NombreDeTipo extiende T1, T2

El tipo es mutable o inmutable


Propiedades
o NombreDePropiedad, Tipo, Consultable o no, derivada o no. Un posible comentario.
Restricciones.
o
Operaciones

o
Criterio de Igualdad: detalles

Introduccin a la Programacin

Representacin como cadena: detalles


Orden natural: si lo tiene especificar detalles
Orden alternativo: si lo tiene, especificar detalles

En el esquema anterior el criterio de igualdad y la representacin como cadena estn relacionados con el
tipo Object, mientras que el orden natural est relacionado con el tipo Comparable, y el orden alternativo
con el tipo Comparator. Estos tipos los veremos con ms detalles en los siguientes apartados.
2. El tipo Object
En Java existe una clase especial llamada Object. Todas las clases que definamos y las ya definidas heredan
de Object, es decir, implcitamente Object es un tipo al que extienden todas las clases Java. Como cualquier
tipo, Object proporciona una serie de mtodos pblicos, no static. Aunque tiene ms mtodos, en este Tema
nos vamos a centrar solamente en tres de esos mtodos: equals, hashCode y toString. Veremos sus
propiedades, las restricciones entre ellos y la forma de redisearlos para que se ajusten a nuestras
necesidades. La signatura de estos mtodos es1:
boolean equals(Object o);
int hashCode();
String toString();
Como el tipo Object es ofrecido por todos los objetos que creemos, los mtodos anteriores estn disponibles
en todos los objetos, es decir, todos los objetos heredan los mtodos equals, hashCode y toString de la clase
Object. Estos mtodos tienen definido un comportamiento por defecto. Veamos para qu se utilizan cada
uno de estos mtodos:

El mtodo equals(Object o) se utiliza para decidir si el objeto es igual al que se le pasa como parmetro.
Recordemos que para decidir si dos objetos son idnticos se usa el operador ==.
El mtodo hashCode() devuelve un entero, que es el cdigo hash del objeto. Todo objeto tiene, por lo
tanto, un cdigo hash asociado.
El mtodo toString() devuelve una cadena de texto que es la representacin exterior del objeto. Cuando
el objeto se muestre en la consola tendr el formato indicado por su mtodo toString correspondiente.

Todos los objetos ofrecen estos tres mtodos. Por lo tanto es necesaria una buena comprensin de sus
propiedades y un buen diseo de los mismos.
Propiedades y restricciones.
Propiedades de equals:

Reflexiva: Un objeto es igual a s mismo. Es decir, para cualquier objeto x, distinto de null, se debe
cumplir que x.equals(x) es true y x.equals(null) es false.

Puede ver el resto de mtodos de Object en la documentacin de la API de Java:


http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html

3. Diseo de Tipos I

Simtrica: Si un objeto es igual a otro, el segundo tambin es igual al primero. Es decir, para dos objetos
cualesquiera x e y, distintos de null, se debe cumplir que x.equals(y) => y.equals(x). Mltiples
invocaciones de x.equals(y) deben devolver el mismo resultado si el estado de x e y no ha cambiado.
Transitiva: Si un objeto es igual a otro, y este segundo es igual a un tercero, el primero tambin ser
igual al tercero. Es decir para tres objetos x, y, z, distintos de null, se debe cumplir que x.equals(y)&&
y.equals(z) => x.equals(z).

Propiedades de equals/toString:

Si dos objetos son iguales, sus representaciones en forma de cadena tambin deben serlo. Es decir, para
dos objetos cualsequiera x e y, distintos de null, se debe cumplir que x.equals(y) =>
x.toString().equals(y.toString()).

Propiedades de equals/hashCode:

Si dos objetos son iguales, sus cdigos hash tienen que coincidir. La inversa no tiene por qu ser cierta.
Es decir, para dos objetos cualesquiera x e y, distintos de null, se debe cumplir que x.equals(y) =>
x.hashCode() == y.hashCode(). Sin embargo, no se exige que dos objetos no iguales produzcan cdigos
hash desiguales, aunque hay que ser consciente de que se puede ganar mucho en eficiencia si en la
mayora de los casos objetos distintos tienen cdigos hash distintos.

Las propiedades y restricciones anteriores son muy importantes. Si no se cumplen, el programa que
diseemos puede que no funcione adecuadamente. Todos los tipos ofrecidos en la API de Java tienen un
diseo adecuado de esos tres mtodos. Pero recordemos que esos tres mtodos estn slo disponibles en
los tipos que extienden Object. Es decir, en los tipos que definen objetos y no estn disponibles en los tipos
primitivos. Por lo tanto, esos mtodos ya estn disponibles en Integer, Long, Float, Double y String, pero no
en los tipos int, long, float y double.
Veamos un ejemplo con la implementacin en el tipo Punto del tema 1, el esquema de diseo del tipo, ahora
sera:
Tipo Punto
Propiedades:
o Coordenada X: Double, consultable y modificable.
o Coordenada Y: Double, consultable y modificable.
Otras operaciones:
o distanciaAOtroPunto (Double p): Double, devuelve la distancia del punto que invoca al mtodo
al punto p.
Representacin como cadena: (coordenadaX, coordenadaY)
Criterio de igualdad: Dos puntos son iguales si sus coordenadas X son iguales y sus coordenadas Y son
iguales.
Teniendo la descripcin anterior del tipo Punto, los mtodos toString, equals y hashCode que deberan
incluirse en la clase PuntoImpl son los siguientes:

Introduccin a la Programacin

Ejemplo 1 : Mtodos toString, equals y hashCode para el tipo Punto

public String toString(){


String s;
s="("+ getX()+","+getY()+")";
return s;
}
public boolean equals(Object o){
boolean r = false;
if(o instanceof Punto){
Punto p = (Punto) o;
r = this.getX().equals(p.getX()) &&
this.getY().equals(p.getY());
}
return r;
}
public int hashCode(){
return getX().hashCode()*31+getY().hashCode();
}

Veamos con un poco de ms detalle el cdigo anterior, del que comentaremos algunos detalles:

En relacin a la implementacin de equals :


o

En relacin a la implementacin de toString:


o

Podemos estar seguros que el casting a Punto no disparar excepciones puesto que se hace
despus de comprobar que objeto ofrece ese tipo. Evidentemente si p no es de tipo Punto el
resultado es false.
Hemos supuesto que sus propiedades no pueden tomar el valor null. Si esto no fuera as, se
disparara una excepcin en getX().equals(p1.getX()) puesto que se intentara invocar el
mtodo equals sobre un objeto null. Eclipse proporciona de forma automtica un cdigo ms
completo que tiene en cuenta la posibilidad de que el objeto a comparar, o algunos de los
atributos que participan en la igualdad, sean null.

La cadena resultante en el mtodo toString se debe calcular a partir de los resultados devueltos
por los correspondientes toString de las propiedades involucradas en la igualdad y,
posiblemente, otras propiedades derivadas de las mismas.
En este caso no es necesario invocar el mtodo toString porque cuando un tipo objeto est
dentro de una operacin con otros operandos de tipo String el compilador llama
automticamente al mtodo. Es decir, en ese contexto el compilador convierte
automticamente el tipo dado a String.

En relacin a la implementacin de hashCode :


o

El hashCode se calcula a partir de las propiedades involucradas en la igualdad. Si hay ms de una


podemos seguir la regla: El hashCode resultante es igual al hashCode de la primera propiedad
ms 31 por el hashCode de la segunda propiedad ms 31*31 por el hashCode de la tercera
propiedad, etc. Alternativamente al 31 se podra haber escogido otro nmero primo no muy
grande. El escoger un nmero primo hace que el hashCode calculado se disperse

3. Diseo de Tipos I

adecuadamente. Es decir, que los hashCode de dos objetos distintos sean en la mayora de los
casos distintos.
Un ejemplo de invocacin a equals es el que se muestra a continuacin:
Ejemplo 2. Ejemplo de invocacin de equals

public TestIgualdad extends Test{


public static void main (String [] args){
Punto p1 = new PuntoImpl (6.0, 4.0);
Punto p2 = new PuntoImpl (6.0, 4.0);
if (p1.equals(p2) && p1!=p2){
mostrar(p1 + y + p2 + son iguales pero no idnticos);
}
}

3. El tipo Comparable
El tipo Comparable un orden a los objetos de un tipo creado por el usuario, al que llamaremos orden
natural. Java ya proporciona un orden natural a los tipos envoltorio como Integer y Double o al tipo
inmutable String (que extienden a Comparable) permitiendo que, por ejemplo, se puedan ordenar cuando
estn sobre una Lista o array.
El tipo Comparable est definido como2:
package java.lang;
public interface Comparable<T>{
int compareTo(T o);
}

El tipo Comparable est incluido en el paquete java.lang de Java y se compone de un slo mtodo: el
mtodo compareTo. El tipo Comparable usa tipos genricos y sirven para una relacin de orden total sobre
los objetos de un tipo dado. El tipo Comparable sirve para establecer el orden natural de un tipo dado, y su
implementacin tiene que cumplir una serie de restricciones:

El mtodo compareTo debe disparar la excepcin NullPointerException cuando toma como parmetro un
valor null.
compareTo compara dos objetos this y p2 y devuelve un entero que es:
Negativo si this es menor que p2

Puede ver la documentacin del tipo Comparable en la API de Java:


http://docs.oracle.com/javase/7/docs/api/java/lang/Comparable.html

Introduccin a la Programacin

Cero si this es igual a p2


Positivo si this es mayor que p2
equals/compareTo: El orden natural definido debe ser coherente con la definicin de igualdad. Si equals
devuelve true, compareTo debe devolver cero. Aqu tambin incluimos, tal como se recomienda en la
documentacin de Java, la inversa. Es decir, que si compareTo devuelve cero, entonces equals devuelve
true. Esto lo podemos enunciar diciendo que la expresin siguiente es verdadera para cualquier par de
objetos x e y: (x.compareTo(y) == 0)(x.equals(y)).

En general, para implementar el mtodo compareTo usaremos los mtodos compareTo de las propiedades
involucradas en la igualdad o algunas otras derivadas. Un orden natural adecuado puede ser comparar en
primer lugar por una propiedad elegida arbitrariamente, si resulta cero comparar por la segunda propiedad,
etc. Veamos un ejemplo, definiendo el tipo Persona con el esquema de diseo de tipos usado en este tema.
Tipo Persona
Propiedades:
o DNI: String, consultable.
o Nombre: String, consultable y modificable.
o Apellidos: String, consultable y modificable.
Representacin como cadena: apellidos, nombre (dni)
Criterio de igualdad: Dos personas son iguales si sus dnis son iguales, sus apellidos son iguales y sus
nombres.
Criterio de ordenacin natural: Por apellidos, nombre y DNI.
Lo primero que debemos modificar respecto al esquema de diseo de tipos del tema 1 es su interfaz, ya que
al tener definido el tipo un orden natural tiene que extender a Comparable):
Ejemplo 3. Diseo de la interfaz Persona extendiendo a Comparable

public interface Persona extends Comparable<Persona> {


String getDNI();
String getNombre();
String getApellidos();
void setNombre(String nombre);
void setApellidos(String apellidos);
}

Los mtodos que habra que aadir a la clase PersonaImpl seran los relacionados con Object, y compareTo.
Ejemplo 4. Mtodos toString, equals, hashCode y compareTo en PersonaImpl

public String toString() {


String s= getApellidos()+", "+getNombre()+ "("+getDNI()+")";
return s;
}
public boolean equals(Object o){
boolean r = false;
if(o instanceof Persona){
Persona p = (Persona) o;
r = this.getDNI().equals(p.getDNI()) &&
this.getNombre().equals(p.getNombre()) &&
this.getApellidos().equals(p.getApellidos()) &&;

3. Diseo de Tipos I

}
return r;
}
public int hashCode(){
return getDNI().hashCode()+ getApellidos().hashCode()*1+
getNombre().hashCode()*31*31;
}
public int compareTo(Persona p) {
int r;
if(p==null){
throw new NullPointerException();
}
r = getApellidos().compareTo(p.getApellidos());
if (r == 0) {
r = getNombre().compareTo(p.getNombree());
if (r == 0){
r = getDNI().compareTo(p.getDNI());
}
}
return r;
}

Note que el orden natural para el tipo Persona deber ser compatible con equals y, por tanto, deber tener
en cuenta las mismas propiedades escogidas para definir el criterio de igualdad.
Un ejemplo de uso del mtodo compareTo es el siguiente:
Ejemplo 5. Ejemplo de uso del mtodo compareTo

public TestCompareTo extends Test{


public static void main (String [] args){
Persona p1 = new PersonaImpl (222222222-R, John, Doe);
Persona p2 = new PersonaImpl (111111111-A, Jane, Doe);
if (p1.compareTo(p2)>0){
mostrar(p1 + va despus de + p2);
}
}

4. El tipo Comparator
El Comparator tambin sirve para proporcionar un orden a los objetos de un tipo creado por el usuario, y
sirve para definir un criterio de ordenacin alternativo al proporcionado por el criterio de ordenacin
natural. El tipo Comparator est incluido en el paquete java.util y, aunque tiene un mtodo equals,
solamente usaremos el mtodo compare. Su definicin es la siguiente3:

Puede obtener ms informacin del tipo Comparator en la documentacin de la API de Java:


http://docs.oracle.com/javase/7/docs/api/java/util/Comparator.html

Introduccin a la Programacin

package java.util;
public interface Comparator<T>{
int compare(T o1, T o2);

El tipo Comparator tambin usa tipos genricos y tambin define, al igual que Comparable, una relacin de
orden total. El mtodo compare compara los dos objetos que toma como parmetro y su implementacin
tiene que cumplir los siguientes requisitos:

compare compara dos objetos o1 y o,2 y devuelve un entero que es:


Negativo si o1 es menor que o2 , segn el criterio de ordenacin alternativo definido
Cero si o1 es igual a o2, segn el criterio de ordenacin alternativo definido
Positivo si o1 es mayor que o2, segn el criterio de ordenacin alternativo definido

equals/compare: Para el diseo de un Comparator, Java propone lo siguiente:


It is generally the case, but not strictly required that (compare(x,y)==0) == (x.equals(y)).
Generally speaking, any comparator that violates this condition should clearly indicate this fact. The
recommended language is "Note: this comparator imposes orderings that are inconsistent with equals."

Esta recomendacin tiene el problema de que si hacemos un Comparator coherente con equals y ste debe
ser coherente con compareTo.
Un criterio de ordenacin alternativo para Persona puede ser ordenar primero por DNI, luego por apellidos,
y luego por nombre. Un comparador para especificar este criterio de ordenacin alternativo es:
Ejemplo 6. Criterio de ordenacin alternativo para Persona.

import java.util.Comparator;
public class ComparadorPersonaDNI implements Comparator<Persona> {
public int compare(Persona p1, Persona p2){
int r;
r = p1.getDNI().compareTo(p2.getDNI());
if (r ==0 ){
r= p1.getApellidos().compareTo(p2.getApellidos());
if (r == 0){
r=p1.getNombre().compareTo(p2.getNombre());
}
}
return r;
}
}

Como podemos comprobar la implementacin anterior consistente con la igualdad.


Un ejemplo de uso de Comparator es el siguiente:
Ejemplo 7. Ejemplo de uso de Comparator

public TestCompare extends Test{

3. Diseo de Tipos I

public static void main (String [] args){


Persona p1 = new PersonaImpl (222222222-R, John, Doe);
Persona p2 = new PersonaImpl (111111111-A, Jane, Doe);
Comparator<Persona> c = new ComparadorPersonaDNI();
if (c.compare(p1, p2)>0){
mostrar(p1 + va despus de + p2);
}
}

Si quisiramos definir un criterio de ordenacin alternativo para ordenar las personas exclusivamente por su
nombre, tendramos un comparador que no es consistente con la igualdad. En este caso, si queremos
conseguir la consistencia con equals (es decir, que si el comparador devuelve cero, equals devuelve true)
hacemos una comparacin adicional, aunque la definamos explcitamente en el criterio de ordenacin
alternativo. Esta comparacin se har si los objetos son iguales segn el criterio de ordenacin alternativo.
En este caso se desempata con el orden natural del tipo. Con esto conseguimos, al menos que si compare da
cero entonces equals es true. As un comparador para ordenar las personas por su nombre sera:
Ejemplo 8. Comparador con desempate usando el orden natural.

import java.util.Comparator;
public class ComparadorPersonaNombre implements Comparator<Persona> {
public int compare(Persona p1, Persona p2){
int r;
r = p1.getNombre().compareTo(p2.getNombre());
if (r ==0 ){
r= p1.compareTo(p2);
}
return r;
}
}

Note que esta solucin del desempate con compareTo solamente es posible si el tipo tiene definido un
orden natural.

5. Ordenacin de arrays con la clase de utilidad Arrays.


Uno de los usos habituales de los tipos Comparable y Comparator es ordenar los objetos que estn
organizados en colecciones o agregados. Como ya sabemos del tema anterior para modificar el orden de los
elementos en un array java proporciona la clase de utilidad Arrays4 con los siguientes mtodos estticos.
package java.util;
public class Arrays {
public static <T> List<T> asList(T...a);
//Existen versiones para double, float, char, byte, long y Object de:
// binarySearch, equals, fill, sort, toString
public static int binarySearch(int[] a, int key);
4

Ver el resto de mtodos en: http://docs.oracle.com/javase/7/docs/api/java/util/Arrays.html

10

Introduccin a la Programacin

public
public
public
public
public
public
public
public
public
public

static
static
static
static
static
static
static
static
static
static

int binarySearch(int[] a, int fromIndex, int toIndex, int key);


boolean equals(int[] a, int[] a2);
void fill(int[] a, int val);
void fill(int[] a, int fromIndex, int toIndex, int val);
void sort(int[] a);
void sort(int[] a, int fromIndex, int toIndex);
void sort(Object[] a);
void sort(Object[] a, int fromIndex, int toIndex);
void sort(T[] a, Comparator<? super T> c);
void sort(T[] a, int fromIndex, int toIndex, Comparator<? super T> c);

public static String toString(int[] a);


...
}

Un ejemplo de uso de estos mtodos para ordenar un array es el siguiente:


public TestOrdenacion extends Test{
public static void main (String [] args){
Persona p1=new PersonaImpl("31122334-W","Antonio","Garca Maratn");
Persona p2=new PersonaImpl("34423123-V","Mara","Prez Pia");
Persona p3=new PersonaImpl("38962334-W","Eva","Garca Morn);
Persona p4=new PersonaImpl("34435723-V","Eugenia","Gmez Titos");
Persona[] v = {p1, p2, p3, p4};
mostrar(Arrays.toString(v));
Arrays.sort(v);
mostrar("El array tras ordenar segn criterio de orden natural: ");
mostrar(Arrays.toString(v));
Arrays.sort(v, new ComparatorPersonaNombre());
mostrar("El array tras ordenar segn criterio alternativo de nombre: ");
mostrar(Arrays.toString(v));
}
}

Note que hay dos versiones del mtodo sort: una que no tiene un comparador como argumento, y que, por
lo tanto, ordena por el criterio de ordenacin natural, y otra, con un comparador, que ordena segn un
criterio de ordenacin alternativo.
6. Ejercicios
1. Ample el tipo Libro definido en el Tema 1, para que tenga en cuenta las siguientes propiedades y
criterios, y sabiendo que ahora el tipo es Comparable.

Propiedades:
o ISBN, de tipo cadena, consultable. Debe tener obligatoriamente 0, 10 13 caracteres
o Ttulo, de tipo cadena, consultable y modificable.
o Autor, de tipo Persona, consultable y modificable.
o Nmero de pginas, de tipo entero, consultable y modificable. Debe ser mayor que cero.
o Precio, de tipo real, consultable y modificable. Debe ser mayor o igual que cero.
o Es best-seller, de tipo booleano, consultable y modificable.

3. Diseo de Tipos I

Representacin como cadena: ISBN seguido de un guin y ttulo


Criterio de igualdad: Dos libros son iguales si tienen el mismo ttulo y ISBN
Orden natural: Por ttulo e ISBN
Orden alternativo: Precio y best-seller.

2. Tipo Rectangulo

Propiedades:
o Lado A: Double, consultable y modificable. Debe ser mayor o igual que cero.
o Lado B: Double, consultable y modificable. Debe ser mayor o igual que cero.
o Centro: Punto, consultable y modificable
o Angulo con Eje X: Double, consultable y modificable
o Area : Double, consultable, derivada, se calcula como el producto de los lados.
Representacin como cadena: lados, centro y ngulo separados por comas y entre llaves
Criterio de igualdad: Dos rectngulos son iguales si tienen los mismos lados, centro y ngulo
Criterio de ordenacin natural: No tiene.
Orden alternativo: rea.

11

Das könnte Ihnen auch gefallen