04.03.11 Besondere Methoden (equals, hashCode und toString)
Die Ausgabe von toString beeinflussen
Manchmal ist es nützlich, wenn man die Ausgabe der toString
-Methode anpassen kann, also zu entscheiden was, und in welcher Reihenfolge es angezeigt wird. Bei unserer Person
könnte man z. B. Attribute setzen, die bestimmen, ob der Vor- oder Nachname zuerst, und ob das Alter auch ausgegeben werden soll. Das ist auch gleichzeitig eine gute Gelegenheit, um die Verwendung von static nochmal in Ihr Gedächtnis zu rufen. Denn bei diesen Variablen sollte es sich um Klassenattribute handeln, da die Ausgabe aller Personen angepasst werden soll – und nicht nur von einzelnen. Legen Sie sich hierzu in Ihrer Klasse die entsprechenden Klassenattribute mit Gettern und Settern an:
public class Person { ... private static boolean printAge = false; private static boolean printFirstnameFirst = false; ... public static boolean isPrintAge() { return Person.printAge; } public static void setPrintAge(boolean printAge) { Person.printAge = printAge; } public static boolean isPrintFirstnameFirst() { return Person.printFirstnameFirst; } public static void setPrintFirstnameFirst(boolean printFirstnameFirst) { Person.printFirstnameFirst = printFirstnameFirst; } ... }
Jetzt muss noch die toString
-Methode dahingehend angepasst werden, dass sie ihren Rückgabewert an die neuen Klassenattribute anpasst:
public String toString() { String retVal = ""; if (Person.printFirstnameFirst) { retVal = this.firstname + " " + this.lastname; } else { retVal = this.lastname + ", " + this.firstname; } if (Person.printAge) { retVal += ", " + this.age + " Jahre"; } return retVal; }
Die Klasse Person
sieht nun so aus:
public class Person { private String firstname = null; private String lastname = null; private int age = 0; private static boolean printAge = false; private static boolean printFirstnameFirst = false; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public static boolean isPrintAge() { return Person.printAge; } public static void setPrintAge(boolean printAge) { Person.printAge = printAge; } public static boolean isPrintFirstnameFirst() { return Person.printFirstnameFirst; } public static void setPrintFirstnameFirst(boolean printFirstnameFirst) { Person.printFirstnameFirst = printFirstnameFirst; } public String toString() { String retVal = ""; if (Person.printFirstnameFirst) { retVal = this.firstname + " " + this.lastname; } else { retVal = this.lastname + ", " + this.firstname; } if (Person.printAge) { retVal += ", " + this.age + " Jahre"; } return retVal; } }
Um unsere neue Funktionalität zu testen, passen wir zum Schluss noch unsere Main-Methode an:
public static void main(String[] args) { Person[] persons = new Person[3]; persons[0] = new Person(); persons[1] = new Person(); persons[2] = new Person(); persons[0].setAge(21); persons[0].setFirstname("Andreas"); persons[0].setLastname("Pries"); persons[1].setAge(26); persons[1].setFirstname("Sebastian"); persons[1].setLastname("Würkner"); persons[2].setAge(20); persons[2].setFirstname("Stefan"); persons[2].setLastname("Kiesel"); for (int i = 0; i < persons.length; i++) { System.out.println(persons[i]); } Person.setPrintFirstnameFirst(true); for (int i = 0; i < persons.length; i++) { System.out.println(persons[i]); } Person.setPrintAge(true); for (int i = 0; i < persons.length; i++) { System.out.println(persons[i]); } }
Und erhalten folgende Ausgabe:
Pries, Andreas
Würkner, Sebastian
Kiesel, Stefan
Andreas Pries
Sebastian Würkner
Stefan Kiesel
Andreas Pries, 21 Jahre
Sebastian Würkner, 26 Jahre
Stefan Kiesel, 20 Jahre
Besserer Stil wäre:
Hallo m3,
danke für Ihren Kommentar! Da das Java Blog Buch ein Buch ist, sollten die Kapitel mehr oder weniger aufeinander aufbauen. Leider wird
instanceof
erst später im Kapitel 04.05 Vererbung angesprochen, weshalb ich mich gegen die Verwendung voninstanceof
entschieden habe. Aber selbstverständlich funktioniert es auch mitinstanceof
, da haben Sie natürlich Recht.Eine Anmerkung zu Ihrem Code/Kommentar im Code habe ich aber trotzdem:
>> den Kram darüber braucht man nicht – null wird durch instanceof geregelt
Dennoch sollte überprüft werden, ob es sich beim übergebenen Objekt um das selbe Objekt wie
this
handelt, da dies vom contract so verlangt wird.Gruß
Stefan
Hallo Stefan,
Ich verstehe das ein Prüfung, ob es sich um das selbe Objekt handelt, sinnvoll sein kann – gerade wenn der Vergleichsalgorithmus zeitaufwendig ist (hier nicht der Fall).
Ich verstehe jedoch nicht, was du mit „contract“ meinst.
Gruß
m3
Hallo m3,
genau das ist der Grund, warum man überprüfen sollte, ob es sich um das identische Objekt handelt. Der „contract“ ist der Vertrag bzw. die Vorgaben von Sun, wie
equals
implementiert werden sollte. Dieser wird auf der zweiten Seite dieses Kapitels unter dem Punkt Vertrag/contract für hashCode und equals besprochen.Gruß
Stefan
Ah ok, danke
Gruß
m3
Sollten Attribute, die vom Typ float oder double sind nicht besser mit Float.compare bzw. Double.compare verglichen werden und abhängig vom Ergebnis entschieden werden, ob die betrachteten Attribute als gleich oder unterschiedlich gelten?
Hallo Thomas,
wirft man einen Blick in den Quellcode von
Float.compare
stellt man fest, dass hier nicht diefloat
-Werte sondern die Bit-Repräsentationen in Form vonIntegern
verglichen werden. Sie haben also recht, dassFloat.compare
(und analog dazu auch Double.compare) etwas anderes als ein Vergleich mit==
ist. In der Praxis fällt dies jedoch kaum ins Gewicht, weshalb ich den Artikel gerne unverändert, und Ihren Kommentar als zusätzlichen Hinweis da stehen lassen würde.Gruß
Stefan
Der Gebrauch von instanceof in equals()-Methoden (und dadurch die Miterfassung von Subklassen im Vergleich) ist schlecht, weil auch dadurch der Kontrakt der equals()-Methode verletzt wird. Siehe dazu „Effective Java, Second Edition“, Rezept 8.
Der im Artikel gewählte Ansatz ist der Empfohlene.
Hallo Tobias,
vielen Dank für die zusätzliche Information.
Gruß
Stefan