2016-04-02 12 views
4

Bitte sagen Sie, was hier passiert. Ich habe eine Person Klasse, die ich als Schlüssel in TreeMap verwende. Ich habe Comparable auch so implementiert, dass TreeMap Sortieren kann.Warum Java TreeMap nicht alle eingefügten Einträge druckt

public class Person implements Comparable{ 

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

Jetzt habe ich TreeMap und addierten Werte darin als:

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); 

Nach direkt Drucken mit System.out.println(treeMap); Iam nur den zuletzt eingefügten Wert, dh

bekommen

Ausgang:{[email protected]=String4}

Ich weiß Schlüssel sollten anders sein, aber neuer Betreiber immer s erstelle ein neues Objekt, also denke ich, es ist in Ordnung. Aber ich bin hilflos herauszufinden, was hier los ist.

Antwort

2

Wahrscheinlich platzieren Sie Elemente in der Map rückwärts und würden höchstwahrscheinlich das Objekt Person als Wert und den String als Schlüssel verwenden. Aber zuerst müssen Sie Ihr Person-Objekt mit einem Konstruktor erweitern, damit Sie mindestens den Namen und eventuell das Alter festlegen können. Fügen Sie einen Konstruktor `Person ':

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

Dann können Sie neu anordnen, wie Sie Elemente in die Karte hinzufügen:

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

Zusätzlich TreeMap verwendet die compareTo Methode, um zu bestimmen, wo die Eingabe platzieren in der Karte für die Schlüssel. Wenn Sie also das Objekt Person als Schlüssel verwenden möchten, müssen Sie die compareTo-Methode implementieren. Aber Ihre compareTo Methode ist nicht richtig implementiert und einfach liefert 0 für jedes Element, so dass Ihre Elemente jeweils anderen Standort in der Karte zu überschreiben:

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

Sie müssen richtig die Methode Inhalte implementieren (Daraus ergibt sich die TODO-Anweisung).

Vielleicht eine Sozialversicherungsnummer (SSN) an die Person-Klasse hinzufügen:

Long ssn; 

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

public Long getSsn(){ 
    return ssn; 
} 

Dann sind Sie auf ssn vergleichen könnte:

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

Aber wenn Sie nur eine Art von Kombination erstellen möchten mit dem, was Sie haben, verketten vielleicht den Namen und das Alter zu versuchen Einzigartigkeit zu haben:

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

Die 'compareTo' Methode ist nicht die Antwort. Siehe meine Antwort. – 4castle

+0

Ja, ich verstehe deinen Standpunkt. Ich habe die Antwort aktualisiert, um weitere Informationen hinzuzufügen. Unabhängig davon sollte die compareTo-Methode implementiert und nicht ausgeschlossen werden. Also habe ich Informationen dazu hinzugefügt. – pczeus

+0

Dies funktioniert immer noch nicht, der Standardkonstruktor legt keine ssn-Nummer fest. Verwenden Sie meine Antwort – 4castle

2

Sie haben die Methode toCompare falsch überschrieben. Es gibt immer 0 zurück. So werden alle Objekte in der Struktur als gleich interpretiert und Ihre treeMap enthält immer nur den Wert, der zuletzt hinzugefügt wurde.

Ich schlage vor, Sie betrachten die kompakte (aber nicht allgemein als @ 4castle notiert) Lösung.

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

Wenn Sie die erste Zeile der Klassendeklaration zu

public class Person implements Comparable<Pesron> 
+0

Dies würde immer noch Personen mit dem gleichen Namen und Alter löschen. Es muss ein eindeutiges Feld für jede "Person" geben, um dies vollständig robust zu machen. – 4castle

+0

@ 4castle, ich kümmere mich nicht darum. Es ist nur ein Lernbeispiel und die reale Klasse wird nicht nur 2 Instanzmitglieder enthalten. – Andrew

+0

Es wäre nicht so schwer zu implementieren, fügen Sie einfach einen dritten Fall für if 'name.equals (o.name)' dann verwenden Sie eine ID-Nummer oder etwas. – 4castle

0

Keys sind nicht eindeutig auf der Grundlage ihrer Speicheradresse geändert wird, sind sie auf einen eindeutigen Wert mit einzigartigen basiert. Alle Ihre Person Objekte sind praktisch identisch, aber was mehr ist, alle Ihre Person Objekte behaupten, "gleich" zu anderen Person Objekt angesichts Ihrer aktuellen compareTo Implementierung (0 bedeutet gleich).

Die Reihenfolge der Parameter für die Methode put ist der Schlüssel zuerst, Wert der Sekunde. Sie müssen die put Anweisungen neu anordnen, so dass etwas Einzigartiges vor dem (der Zeichenfolge) ist, und daher alle Einträge eindeutig machen.

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

Jetzt gibt es keine Notwendigkeit, Comparable oder haben die compareTo Methode in Person zu implementieren.

Wenn Sie verlangen, dass die Person Objekt ein Schlüssel sein, werden Sie jedes einzigartig machen müssen, indem sie eine eindeutige Variable, mit der Angabe richtig die compareTo Methode zu verwenden. Die beste Lösung besteht darin, jedem Objekt Person eine erforderliche ID-Nummer hinzuzufügen oder andernfalls name und age als eindeutigen Wert für das Objekt zu verwenden. Fügen Sie auf diesem 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; 
} 

mit

public class Person implements Comparable<Person> 
+0

Ich denke OP will "Person" als Schlüssel verwenden, schrieb er darüber. – Andrew

+0

@AndrewTobilko Ich habe meine Antwort aktualisiert, um eine ID-Nummer vorzuschlagen, da die Namen nicht garantiert eindeutig sind. – 4castle

+0

Nur eine Anmerkung, momentan ist es unmöglich, den Schlüssel richtig zu verwenden, um den Wert mit 'get' wieder zu erhalten. Sie müssen die'Equals'-Methode in 'Person' überschreiben, um den Schlüssel erneut zu finden. – 4castle

2

TreeMap verwendet compareTo Methode von Comparable (nicht equals Methode von Object), wenn er versucht, put ein Element in Map. Da Ihre compareTo Methodenimplementierung 0 für alle Person Objekte zurückgibt, kann in nur ein Element vorhanden sein.

Also, wenn Sie versuchen, mehrere Person Schlüssel zu setzen, TreeMap nur Wert Updates für sie da alle Person Objekte gleich sind (wie pro Ihre Implementierung für compareTo).

Hier Code-Schnipsel für TreeMap.put von 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); 
    } 

So überprüft es zunächst, ob Comparator vorgesehen ist, wenn ja, TreeMapcompare Methode verwendet Schlüssel vergleichen ansonsten verwendet es compareTo Verfahren von Comparable zum Vergleich .