Foros aprenderaprogramar.com
Aprender a programar => C, C++, C#, Java, Visual Basic, HTML, PHP, CSS, Javascript, Ajax, Joomla, MySql y más => Mensaje iniciado por: usuHelp en 01 de Enero 2021, 19:05
-
Hola, una consulta sobre Java.
Teniendo esta clase Jugador:
public class Jugador implements Comparable<Jugador>{
private String nombre, id;
public Jugador(){
this( "", ""); // llama al constructor con dos argumentos
}
public Jugador(String id,String nombre) {
this.id= id;
this .nombre=nombre;
}
public String getNombre(){
return nombre;
}
public void setNombre (String nombre) {
this.nombre = nombre;
}
public void setId(String id ) {
this.id=id;
}
public String getId( ) {
return id;
}
public void mostrar Datos( ) {
System.out.println( "ID: "+id+"\nNombre: "+nombre);
}
@Override
public int compareTo(Jugador o) {
// TOTO Auto-generated method stub
return 0;
}
En el main intento introducir datos de jugadores, introducirlos en un TreeSet e imprimirlos,el problema es que solo introduce el primero. Por ejemplo:
TreeSet <Jugador> listaJugadores = new TreeSet<Jugador>();
Jugador j1 = new Jugador("jA","pepe");
Jugador j2 = new Jugador("jB","juan");
Jugador j3 = new Jugador("jC","maria");
listaJugadores.add(j1);
listaJugadores.add(j2);
listaJugadores.add(j3);
for(Jugador j: listaJugadores) {
j.mostrarDatos();
}
Solo muestra jA Pepe.Gracias por adelantado!
-
Hola,
se debe a que no has completado el método compareTo()
Verás, el TreeSet tiene una peculiaridad y es que SOLO admite elementos que NO estén repetidos.
Pero claro, él por si solo, no es capaz de discernir cuándo un elemento se repite o no.
En este caso trabajamos con objetos Jugador., ¿Cuándo un Jugador es igual a otro?
¿Cuando tienen el mismo nombre?
¿Cuando tiene el mismo ID?
¿Cuando coinciden tanto el nombre como el ID?
Esto TreeSet no lo puede decidir, lo decide el programador
Una forma de hacerlo, es implementando la interfaz Comparable a la clase que está creando.
A Jugador, le has implementado dicha interfaz, bién, pero no has completado el método compareTo().
Así que no has decidido todavía cómo se han de comparar los objetos Jugador.
Has dejado el código que viene por defecto, que hace un return 0.
@Override
public int compareTo(Jugador o) {
// TODO Auto-generated method stub
return 0;
}
Y cuando compareTo() retorna 0, significa que los objetos que se comparan son iguales.
Por tanto, el TreeSet confía ciegamente en lo que este método le dice, y le está diciendo que todos los objetos Jugador que le estás pasando, son iguales.
Y por tanto, el TreeSet solo admite el primero y el resto los rechaza.
Esto se puede comprobar muy fácilmente. Cuando añadimos un objeto al TreeSet, este retorna true si lo admite o false si lo rechaza.
Si pedimos mostrar en pantalla qué es lo que retorna cada vez que hacemos un add()...
public static void main(String[] args) {
TreeSet <Jugador> listaJugadores = new TreeSet<Jugador>();
Jugador j1 = new Jugador("jA","pepe");
Jugador j2 = new Jugador("jB","juan");
Jugador j3 = new Jugador("jC","maria");
System.out.println(listaJugadores.add(j1));
System.out.println(listaJugadores.add(j2));
System.out.println(listaJugadores.add(j3));
for(Jugador j: listaJugadores) {
j.mostrarDatos();
}
}
...veremos que solo admite el primero:
true
false
false
ID: jA
Nombre: pepe
Podemos hacer otro experimento, cambiamos el método compareTo() para que retorne algo que no sea 0:
@Override
public int compareTo(Jugador o) {
// TODO Auto-generated method stub
return 1;
}
Cuando retorna un entero positivo, como el 1, significa que el objeto que recibe como argumento para compararse, es mayor. Por tanto, no son iguales, así que ahora TreeSet si admitirá los tres objetos que le pasamos (aunque en realidad aún no hemos establecido una regla de comparación que sea útil)
Si volvemos a ejecutar el programa, veremos que los tres objetos añadidos retornan true y podemos listarlos en pantalla:
true
true
true
ID: jA
Nombre: pepe
ID: jB
Nombre: juan
ID: jC
Nombre: maria
Aprovechemos la ocasión para hacer otro experimento. Volvemos a cambiar el retorno de compareTo(), esta vez, vamos a pedir que retorne un valor negativo.
@Override
public int compareTo(Jugador o) {
// TODO Auto-generated method stub
return -1;
}
Un valor negativo significa que el objeto que recibe como argumento para compararse, es menor.
¿Qué pasa entonces si volvemos a ejecutar el programa?
true
true
true
ID: jC
Nombre: maria
ID: jB
Nombre: juan
ID: jA
Nombre: pepe
¡¡Voilá!!
Los tres Jugadores se han añadido y además se han ordenado de forma inversa a la que los hemos insertado.
Esto es porque ahora compareTo() le está diciendo a TreeSet que todas las comparaciones resultan en que el nuevo objeto recibido es menor respecto a los que ya hay insertados.
Esta es otra peculiaridad de TreeSet, no solo evita que se repitan elementos, si no que siempre los tiene ordenados de menor a mayor.
La verdad es que este tipo de Set es un encanto :-* je je.
Pero claro, para que lo haga bien, nosotros tenemos que escribir correctamente el método compareTo() y decidir cuáles son las reglas de comparación para nuestra clase.
La pregunta es:
¿Cuándo podemos considerar un Jugador menor o mayor que otro?
Puede depende de cada caso y del criterio del programador, por supuesto..
En este caso, comos los jugadores tienen un ID, que se supone ha de ser único, pues puede ser ese el atributo que consideremos fundamental para comparar Jugadores.
Ahora hay que escribir un código para decidir como compara ese atributo.
Puesto que se trata de un String, y la clase String ya tiene implementada su propia regla de comparación, pues podemos simplemente establecer que se retorne el resultado de comparar los ID, tal cuál establece la clase String:
@Override
public int compareTo(Jugador o) {
return this.id.compareTo(o.id);
}
Los String hacen una comparación lexicográfica, es decir, que la letra a se considera menor que la b, la b es menor que la c, etc..
Vamos, que ordena alfabéticamente de la a a la z, y según cuantas letras tiene cada String.
Si volvemos a ejecutar el programa, y cambiamos los id para insertarlos desordenados alfabéticamente:
public static void main(String[] args) {
TreeSet <Jugador> listaJugadores = new TreeSet<Jugador>();
Jugador j1 = new Jugador("jB","pepe");
Jugador j2 = new Jugador("jC","juan");
Jugador j3 = new Jugador("jA","maria");
System.out.println(listaJugadores.add(j1));
System.out.println(listaJugadores.add(j2));
System.out.println(listaJugadores.add(j3));
for(Jugador j: listaJugadores) {
j.mostrarDatos();
}
}
Veremos que al mostrarlos, se muestran bien ordenados:
true
true
true
ID: jA
Nombre: maria
ID: jB
Nombre: pepe
ID: jC
Nombre: juan
-
Muchas gracias! Ahora me surge otra duda,hay alguna manera de comparar constantes declaradas en una interfaz? Por ejemplo, si tengo subclases con la super como jugador, y en esas subclases tengo las variables declaradas de la interfaz,cada constante calculada de una distinta manera en cada subclase(dependen de los distintos métodos introducidos en cada subclase).Teniendo un ArrayList<Jugador> lleno de los distintos tipos(de las subclases) y los quiero ordenar según una caracteristica que tienen en común,la constante extendida de la interfaz,hay alguna manera de hacer eso? Ya que id o nombre no hay ningún problema pero con las compartidas de la interfaz sí,entiendo que son conceptos distintos pero no soy capaz de llegar a ninguna solución...Gracias!
-
Mmmhhh.. pues posiblemente sí, aunque puede ser algo más complicado.
Si la interfaz la implementa la clase Jugador, y por tanto esta clase tendría esas constantes dentro de su ámbito, entonces si deberían poder usarse como regla de comparación.
Si la interfaz la implementase las clases hijas, y no Jugador, la cosa se complicaría más.
Porque los objetos que están el <Jugador>TreeSet en ese momento son objetos de clase Jugador, que no implementa esa interfaz y por tanto las constantes están fuera de su ámbito. Vamos, que no tiene ni idea de que constantes son.
Habría que complicar un poco el código preguntando en cada caso que tipo de clase hija pertenece con la palabra reservada instanceof y hacer un casting para convertirlo a la clase hija a la que realmente pertenece dicho objeto, y ahora sí se podrían consultar esas constantes.
Si compartes todo tu código, podemos intentar ver cuál sería la mejor solución.