prayerslayer
Oar. Mh.
|
Hiho, ich hab hier eine Klasse SearchItem, welche eine Eigenschaft eines realen Objekts repräsentiert, nach der man suchen kann. Die besteht nur aus einem Namen und einer Methode equals: package search;
public class SearchItem {
private String name;
public String getName() {
return name;
}
// public void setName(String name) {
// this.name = name;
// }
@Override
public String toString() {
return "SearchItem [name=" + name + "]";
}
public SearchItem(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
if (obj == null)
return false;
if (obj instanceof SearchItem) {
System.out.println("iof SearchItem");
System.out.println(name+" equals "+((SearchItem)obj).getName()+"?");
return ((SearchItem)obj).getName().equalsIgnoreCase(this.getName());
}
if (obj instanceof String) {
System.out.println("iof String");
System.out.println(name+" equals "+obj+"?");
return name.equalsIgnoreCase((String)obj);
}
return false;
}
}
Diese SearchItems werden in einem SearchItemSystem verwaltet. package search;
import java.util.*;
public class SearchItemSystem {
private Set<SearchItem> searchItems;
private static SearchItemSystem instance;
private SearchItemSystem() {
searchItems = new HashSet<SearchItem>();
}
/**
* Returns the instance of SearchItemSystem
*
* @return instance
*/
public static SearchItemSystem getInstance() {
if (instance==null)
instance=new SearchItemSystem();
return instance;
}
/**
* Deletes an Item from the system
* @param name The name of the item
* @return true if something was removed
*/
public boolean deleteItem(String name) {
if (name==null)
return false;
SearchItem old = new SearchItem(name);
return searchItems.remove(old);
}
/**
* Edit an SearchItem
*
* @param name The name of the SearchItem
* @param newName The new name
* @return The new item. Null if something went wrong or there was no old item
*/
public SearchItem editItem(String name, String newName) {
if (name==null)
return null;
if (newName==null)
return null;
if (name.equalsIgnoreCase(newName))
return null;
SearchItem oldItem = new SearchItem(name);
if (!searchItems.contains(oldItem))
return null;
searchItems.remove(oldItem);
return createItem(newName);
}
/**
* Returns all items in the system
* @return all items
*/
public Set<SearchItem> getAllItems() {
return searchItems;
}
/**
* Creates a new SearchItem, adds it to the system and returns it.
*
* @param name The name of the SearchItem
* @return The created item, null if there is already such an item
*/
public SearchItem createItem(String name) {
System.out.println("Items: "+searchItems);
if (name==null)
return null;
if (searchItems.contains(name))
return null;
SearchItem si = new SearchItem(name);
System.out.println("new item: "+si);
if (searchItems.contains(si))
return null;
//TODO some evil voodoo magic happens here
if (searchItems.add(si))
return si;
return null;
}
}
Das Problem ist, dass dieser JUnit-Test funktioniert: package search.test;
import search.SearchItem;
import search.SearchItemSystem;
import junit.framework.*;
public class SearchItemSystemTest extends TestCase{
SearchItemSystem sis = null;
SearchItem a = new SearchItem("A");
SearchItem b = new SearchItem("B");
SearchItem c = new SearchItem("C");
public void setUp() {
sis = SearchItemSystem.getInstance();
}
public void testItems() {
assertTrue(".equals isn't working", (new SearchItem("D")).equals(new SearchItem("d")));
assertTrue(".equals isn't working", (new SearchItem("D")).equals("d"));
assertFalse(".equals isn't working", b.equals("C"));
assertTrue(".equals isn't working", b.equals("b"));
assertTrue(".equals isn't working", b.equals(b));
assertFalse(".equals isn't working", b.equals(c));
assertEquals("Null-Item was created", null, sis.createItem(null));
assertEquals("Item A was not created", a, sis.createItem("A"));
assertEquals("Item A was created twice", a, sis.createItem("a"));
assertEquals("Item A was created three times", a, sis.createItem("a"));
}
public static void main(String[] args) {
// TODO Auto-generated method stub
junit.textui.TestRunner.run(SearchItemSystemTest.class);
}
}
Output: iof SearchItem
D equals d?
iof String
D equals d?
iof String
B equals C?
iof String
B equals b?
iof SearchItem
B equals B?
iof SearchItem
B equals C?
Items: []
Items: []
new item: SearchItem [name=A]
iof SearchItem
A equals A?
Items: [SearchItem [name=A]]
new item: SearchItem [name=a]
iof SearchItem
A equals a?
Items: [SearchItem [name=a], SearchItem [name=A]]
new item: SearchItem [name=a]
iof SearchItem
A equals a?
Eigentlich sollte beim 2. und 3. Mal createItem("a") ein Nullpointer herauskommen. Lustigerweise passiert JUnit aber die Passage, wo die equals() Methode der SearchItems überprüft wird. contains() und add() des HashSets überprüfen nicht richtig, ob ein SearchItem schon vorhanden ist - ich dachte immer, die greifen auf equals() zurück, aber dann müsste es ja funktionieren. Entweder ist der Fehler offensichtlich und ich steh auf der Leitung, oder aber hier passiert wirklich evil voodoo magic.  Bitte helfen! tia
Bearbeitet von prayerslayer am 25.05.2010, 20:56
|
DKCH
Administrator ...
|
ohne jetzt was genauer angeschaut zu haben: für ein HashSet solltest du auch hashCode überschreiben, der aus den properties, die in equals verwendet werden, halt einen hash berechnet...
|
Nico
former person of interest
|
glaube auch dass deine equals version nie aufgerufen wird..
|
prayerslayer
Oar. Mh.
|
ohne jetzt was genauer angeschaut zu haben: für ein HashSet solltest du auch hashCode überschreiben, der aus den properties, die in equals verwendet werden, halt einen hash berechnet... Das hab ich noch nie müssen :/ Ich probier das mal. glaube auch dass deine equals version nie aufgerufen wird.. Nawohl, beim add() im Set laut Konsolenoutput schon. //Danke DKCH, diese Methode im SearchItem... @Override
public int hashCode() {
return this.name.toLowerCase().hashCode();
}
...führt zum gewünschten Ergebnis
Bearbeitet von prayerslayer am 25.05.2010, 20:33
|
meepmeep
Here to stay
|
ich weiss nicht mit welcher ide du arbeitest, aber eclipse zum beispiel kann dir equals und hashcode generieren (allerdings nur bis zu einem gewissen grad sinnvoll, in deinem fall aber wahrscheinlich ausreichend)
lg
Bearbeitet von meepmeep am 25.05.2010, 21:05
|
semteX
begehrt die rostschaufel
|
generell ist das überschreiben von equals alleine selten sinnvoll und wird völlig zurecht von "findbugs" (super plugin btw) als bug identifiziert... sobald das ding in nem hashset oder hashmap drin ist, kommst in teufels küche...
|
Nico
former person of interest
|
plugin für welche ide?
|
semteX
begehrt die rostschaufel
|
eclipse
|