2016-04-02 2 views
4

Pls dit ce qui ne va pas ici. J'ai une classe Person que j'utilise comme clé dans TreeMap. J'ai également mis en œuvre Comparable afin que puisse faire le tri.Pourquoi Java TreeMap n'imprime pas toutes ses entrées insérées

public class Person implements Comparable{ 

private String name; 
private int age; 
// getters and setters were omitted 
@Override 
public int compareTo(Object o) { 
    return 0; 
} 
} 

Maintenant, je crée TreeMap et les valeurs ajoutées dans comme:

Map treeMap=new TreeMap<Person,Object>(); 

treeMap.put(new Person(), "String1"); 
treeMap.put(new Person(), "String2"); 
treeMap.put(new Person(), "String3"); 
treeMap.put(new Person(), "String4"); 

System.out.println(treeMap); 

Après l'impression directe à l'aide System.out.println(treeMap); Iam seulement obtenir la dernière valeur insérée à savoir

Sortie:{[email protected]=String4}

Je sais que les clés devraient être différentes mais un nouvel opérateur toujours s créer un nouvel objet, donc je pense que c'est bien. Mais je suis impuissant à comprendre ce qui ne va pas ici.

Répondre

2

Vous placez probablement des éléments dans la carte vers l'arrière et souhaiteriez probablement que l'objet Person soit la valeur et la chaîne comme clé. Mais vous devez d'abord améliorer votre objet Person avec un constructeur pour vous permettre de définir au moins le nom, et peut-être l'âge. Ajouter un constructeur à 'Personne':

public Person(String n, int a){ 
    this.name = n; 
    this.age = a; 
} 

Ensuite, vous pouvez modifier l'ordre comment ajouter des éléments à la carte:

Person p1 = new Person("Bob Jones", 32); 
treeMap.put(p1.getName(), person); 

De plus, TreeMap utilise la méthode compareTo pour déterminer où placer l'entrée dans la Carte pour les clés. Ainsi, si vous avez l'intention d'utiliser l'objet Person comme clé, vous devez implémenter la méthode compareTo. Mais votre méthode compareTo n'est pas implémentée correctement et renvoie simplement 0 pour chaque élément, ce qui provoque vos éléments écrasent chaque emplacement des autres dans la carte:

@Override 
public int compareTo(Object o) { 
    /TODO Auto-generated method stub 
    return 0; 
} 

Vous devez implémenter correctement le contenu de la méthode (d'où la déclaration TODO).

Peut-être ajouter un numéro de sécurité sociale (SSN) à la classe Person:

Long ssn; 

public void setSsn(Long value){ 
    ssn = value; 
} 

public Long getSsn(){ 
    return ssn; 
} 

Ensuite, vous pouvez comparer sur ssn:

@Override 
public int compareTo(Object o) { 
    if(o == null) return 1; 
    Person op = (Person)o; 
    return ssn.compareTo(op.getSsn()); 
} 

Mais si vous voulez juste créer un certain type de combinaison avec ce que vous avez, peut-être concaténer le nom et l'âge pour essayer d'avoir l'unicité:

@Override 
public int compareTo(Object o) { 
    if(o == null) return 1; 
    Person op = (Person)o; 
    return (name + age).compareTo(op.getName() + op.getAge()); 
} 
+0

L'implémentation de la méthode 'compareTo' n'est pas la solution du tout. Vois ma réponse. – 4castle

+0

Oui, je vois votre point. J'ai mis à jour la réponse pour inclure plus d'informations. Quoi qu'il en soit, la méthode compareTo doit être implémentée et non écrasée. J'ai donc ajouté des informations à ce sujet. – pczeus

+0

Cela ne fonctionnerait toujours pas, le constructeur par défaut ne définit pas un nombre ssn. Utilisez ma réponse – 4castle

2

Vous avez incorrectement la méthode toCompare. Il renvoie toujours 0. Ainsi, tous les objets de l'arborescence seront interprétés comme identiques et votre treeMap contient toujours uniquement la valeur qui a été ajoutée la dernière.

Je suggère que vous considériez le compact (mais pas général comme @ 4castle noté) solution.

@Override 
public int compareTo(Person o) { 
    if (age != o.age) return age > o.age ? 1 : -1; 
    return name.compareTo(o.name); 
} 

Si vous avez changé la première ligne de la déclaration de classe à

public class Person implements Comparable<Pesron> 
+0

Cela supprimerait toujours les personnes portant le même nom et l'âge. Il doit y avoir un champ unique pour chaque 'Personne 'pour rendre ceci complètement robuste. – 4castle

+0

@ 4castle, je ne prends pas soin de ça. C'est juste un exemple d'apprentissage et la vraie classe ne contiendra pas seulement 2 membres d'instance. – Andrew

+0

Ce ne serait pas si difficile à implémenter, il suffit d'ajouter un troisième cas pour si 'name.equals (o.name)' utilise alors un numéro d'identification ou quelque chose du genre. – 4castle

0

Les clés ne sont pas uniques en fonction de leur adresse mémoire, ils sont uniques sur la base d'une valeur unique. Tous vos objets sont Personpratiquement identiques, mais ce qui est plus, tous vos objets Person prétendent être « égal » à tout autre objet Person donné l'implémentation actuelle compareTo (0 signifie égal).

L'ordre des paramètres de la méthode put est la première clé, valeur seconde. Vous devez réorganiser les instructions put pour que quelque chose d'unique soit en face (la chaîne), et donc rendre toutes les entrées uniques.

treeMap.put("String1", new Person()); 
treeMap.put("String2", new Person()); 
treeMap.put("String3", new Person()); 
treeMap.put("String4", new Person()); 

Maintenant, il n'y a pas besoin de mettre en œuvre Comparable ou ont la méthode compareTo dans Person.

Si vous avez besoin que l'objet soit Person une clé, vous devrez faire chacun unique en lui donnant une variable unique avec laquelle utiliser la méthode compareTo correctement. La meilleure solution consiste à ajouter un numéro d'ID requis à chaque objet Person ou à utiliser les name et age comme valeur unique pour l'objet. Ajouter sur ce code à Person:

private int id; 
private static int numPeople = 0; 
public Person() { 
    numPeople++; 
    id = numPeople; 
    name = ""; 
} 
@Override 
public int compareTo(Person o) { 
    if (age != o.age) return age > o.age ? 1 : -1; 
    if (!name.equals(o.name) return name.compareTo(o.name); 
    return id > o.id ? 1 : -1; 
} 

avec

public class Person implements Comparable<Person> 
+0

Je pense que OP veut utiliser 'Person' comme une clé, il a écrit à ce sujet. – Andrew

+0

@AndrewTobilko J'ai mis à jour ma réponse pour suggérer un numéro d'identification, car les noms ne sont pas forcément uniques. – 4castle

+0

Juste une note, actuellement il est impossible d'utiliser correctement votre clé pour récupérer la valeur en utilisant 'get'. Vous devrez remplacer la méthode 'equals' dans' Person' afin de retrouver cette clé. – 4castle

2

TreeMap utilise la méthode compareTo de Comparable (non equals méthode de Object) quand il essaie de put un élément dans Map. Comme l'implémentation de la méthode compareTo renvoie 0 pour tous les objets Person, il ne peut y avoir qu'un seul élément dans TreeMap.

Alors, quand vous essayez de mettre plusieurs Person clés, TreeMap seule valeur des mises à jour, puisque pour ce sont les mêmes tous Person objets (selon votre implémentation pour compareTo).

est ici extrait de code pour TreeMap.put de Java-8

// split comparator and comparable paths 
    Comparator<? super K> cpr = comparator; 
    if (cpr != null) { 
     do { 
      parent = t; 
      cmp = cpr.compare(key, t.key); 
      if (cmp < 0) 
       t = t.left; 
      else if (cmp > 0) 
       t = t.right; 
      else 
       return t.setValue(value); 
     } while (t != null); 
    } 
    else { 
     if (key == null) 
      throw new NullPointerException(); 
     @SuppressWarnings("unchecked") 
      Comparable<? super K> k = (Comparable<? super K>) key; 
     do { 
      parent = t; 
      cmp = k.compareTo(t.key); 
      if (cmp < 0) 
       t = t.left; 
      else if (cmp > 0) 
       t = t.right; 
      else 
       return t.setValue(value); 
     } while (t != null); 
    } 

Alors d'abord il vérifie, si Comparator est fourni, si oui, TreeMap utilise la méthode compare pour comparer les clés sinon il utilise la méthode compareTo de Comparable pour la comparaison .