-
Enhancement
-
Resolution: Unresolved
-
P4
-
None
-
1.4.2
-
Cause Known
-
x86
-
windows_xp
Name: rmT116609 Date: 05/11/2004
A DESCRIPTION OF THE REQUEST :
Collection interface implementations such as HashMap, Vector, ArrayList use their own logic to compare objects for add(), remove(), contains() & other methods.
JUSTIFICATION :
If a complex object is stored in a vector & then that object needs to be removed by just using its ID, then the solution requires a knowledge of how the Vector class compares the two objects.
In this case, overriding the equals() method of the complex object will not suffice, since the equality check is done on the ID.
Also the documentation for indexOf(Object elem) does not throw much light, since it does not clearly state as to which objects equals() method is called.
In my case (see example below), since ID is a String, I would need to create a wrapper class and override the equals() method in that class.
My question is: Why all doing this??
It would be much simpler if the collection interface would accept a Comparator (or an interface requiring only an equality check) to specify the comparison logic.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
I should be able to specify how the collection compares objects during add(), remove(), contains() and other operations. Currently the closest way to specify this is using a Comparator (though only an equality check is needed, and comparator provides a total-ordering).
ACTUAL -
Implementations use their own comparison logic
---------- BEGIN SOURCE ----------
import java.util.Vector;
public class Tester {
public Tester() {
}
public static void main(String args[]) throws Exception {
Vector messages = new Vector();
String id = "ID";
String msg = "Test Message";
Message mess = new Message(id, msg);
messages.add(mess);
//Tries to remove object by ID
boolean success = messages.remove(id);
System.out.println("Removal by id: " + success);
//Tries to remove object by reference
if (!success) {
success = messages.remove(mess);
}
System.out.println("Removal by reference: " + success);
}
}
class Message {
String id;
String msg;
public Message(String id, String msg) {
this.id = id;
this.msg = msg;
}
public String getID() {
return id;
}
public String getMessage() {
return msg;
}
// Equals tries to handle case when ID is passed for comparison
// but is never called.
// This is because the ID object (String)
// is tested for equality and not the element in the vector
public boolean equals(Object a) {
if (a instanceof Message) {
return ((Message) a).getID().equals(id);
} else if (a instanceof String) {
return ((String) a).equals(id);
} else {
return false;
}
}
public int hashCode() {
return id.hashCode();
}
}
---------- END SOURCE ----------
CUSTOMER SUBMITTED WORKAROUND :
//Using a thin wrapper which overrides the equals() method
import java.util.Vector;
public class Tester {
public Tester() {
}
public static void main(String args[]) throws Exception {
Vector messages = new Vector();
String id = "ID";
String msg = "Test Message";
Message mess = new Message(id, msg);
messages.add(mess);
//Tries to remove object by ID
boolean success = messages.remove(new ComparisonKey(id));
System.out.println("Removal by id: " + success);
//Tries to remove object by reference
if (!success) {
success = messages.remove(mess);
}
System.out.println("Removal by reference: " + success);
}
}
class Message {
String id;
String msg;
public Message(String id, String msg) {
this.id = id;
this.msg = msg;
}
public String getID() {
return id;
}
public String getMessage() {
return msg;
}
// Equals tries to handle case when ID is passed for comparison
// but is never called.
// This is because the ID object (String)
// is tested for equality and not the element in the vector
public boolean equals(Object a) {
if (a instanceof Message) {
return ((Message) a).getID().equals(id);
} else if (a instanceof ComparisonKey) {
return ((ComparisonKey) a).getKey().equals(id);
} else {
return false;
}
}
public int hashCode() {
return id.hashCode();
}
}
/**
* Key to compare the elements
*/
class ComparisonKey {
String key;
public ComparisonKey(String key) {
this.key = key;
}
public String getKey() {
return key;
}
public boolean equals(Object a) {
if (a instanceof Message) {
return ((Message) a).getID().equals(key);
} else if (a instanceof ComparisonKey) {
return ((ComparisonKey) a).getKey().equals(key);
} else {
return false;
}
}
}
(Incident Review ID: 261455)
======================================================================
- relates to
-
JDK-4771660 (coll) Comparator, Comparable, Identity, and Equivalence
- Open
-
JDK-4269596 (coll) Wanted: A way to customize the equals/hashCode algorithm
- Closed
-
JDK-6355410 Impossible for subclasses to preserve the equals contract
- Closed