[英]Evaluating objects containing Strings with Java ArrayList contains()
I would like to do a deeper String check of Objects to be able to do the following: 我想对Objects进行更深入的String检查,以便能够执行以下操作:
List<MyObj> myList = new ArrayList<MyObj>() {{
add(new MyObj("hello"));
add(new MyObj("world"));
}};
System.out.println(myList.contains("hello")); // true
System.out.println(myList.contains("foo")); // false
System.out.println(myList.contains("world")); // true
But getting false on each one with the following full code 但是使用以下完整代码在每个上面都会出错
/* Name of the class has to be "Main" only if the class is public. */
class Ideone {
public static class MyObj {
private String str;
private int hashCode;
public MyObj(String str) {
this.str = str;
}
public @Override boolean equals(Object obj) {
System.out.println("MyObj.equals(Object)");
if (obj == this) {
return true;
}
if (obj instanceof String) {
String strObj = (String) obj;
return strObj.equals(str);
}
return false;
}
public @Override int hashCode() {
if (hashCode == 0) {
hashCode = 7;
for (int i = 0; i < str.length(); ++i) {
hashCode = hashCode * 31 + str.charAt(i);
}
}
return hashCode;
}
}
public static final MyObj obj1 = new MyObj("hello");
public static final MyObj obj2 = new MyObj("world");
public static void main (String[] args) throws java.lang.Exception {
List<MyObj> myList = new ArrayList<MyObj>() {{
add(obj1);
add(obj2);
}};
System.out.println(myList.contains("hello"));
System.out.println(myList.contains("foo"));
System.out.println(myList.contains("world"));
}
}
If I'm right the List Object should use equals()
and hashCode()
to evaluate containing Objects. 如果我是对的,List Object应该使用equals()
和hashCode()
来计算包含的对象。 So I @Override
them and check their Strings additionally. 所以我@Override
他们并另外检查他们的字符串。 But it never gets into equals()
as there's no output MyObj.equals(Object)
. 但它永远不会进入equals()
因为没有输出MyObj.equals(Object)
。
java.util.ArrayList#indexOf
is used internally in ArrayList for contains()
. java.util.ArrayList#indexOf
在ArrayList内部用于contains()
。
There is a check, 有一张支票,
o.equals(elementData[i])
So there is comparison of string with your object, so String.equals()
is invoked for check of equality. 因此,字符串与您的对象进行比较,因此调用String.equals()
以检查相等性。
You are not fulfilling the equals
contract at all: 你根本没有履行equals
合同:
The equals method implements an equivalence relation on non-null object references: equals方法在非null对象引用上实现等价关系:
So without respecting the contract for the method you can't expect intended behavior. 因此,如果不尊重方法的合同,您就不能指望预期的行为。
Just for example, what guarantees you that equals is going to be called on the object contained in the ArrayList and not in the other way, eg "hello".equals(new MyObj("hello"))
. 例如,什么保证你将在ArrayList中包含的对象上调用equals,而不是以其他方式"hello".equals(new MyObj("hello"))
,例如"hello".equals(new MyObj("hello"))
。 You have no guarantees about it but since equals
is normally supposed to be symmetric than you shouldn't mind. 你不能保证它,但是因为equals
通常被认为是对称的而不是你不应该介意的。
As pointed out by others, the problem is that your equals method is never called. 正如其他人所指出的那样,问题是你的 equals方法永远不会被调用。 When you invoke myList.contains("hello")
, ArrayList
checks whether "hello".equals(<MyObj>)
, not the other way around. 当你调用myList.contains("hello")
, ArrayList
检查"hello".equals(<MyObj>)
,而不是相反。
Instead, I recommend implementing your equals
method properly , so that two MyObject
instances with equal value
are considered equal, and then create a helper method like this: 相反,我建议正确实现你的equals
方法,以便将两个具有相等value
MyObject
实例视为相等,然后创建一个这样的辅助方法:
public boolean myContains(List<MyObj> list, String value) {
return list.contains(new MyObj(value));
}
List<MyObj> myList = new ArrayList<MyObj>()
is a list of MyObj
, so you need to use MyObj
while checking myList.contains
: 是的清单MyObj
,所以你需要使用MyObj
同时检查myList.contains
:
System.out.println(myList.contains(new MyObj("hello")));
System.out.println(myList.contains(new MyObj("foo")));
System.out.println(myList.contains(new MyObj("world")));
You're asking the List to compare a String
to a MyObj
... They are never going to be "equal". 你要求List将String
与MyObj
进行比较......它们永远不会“相等”。 Try a map instead: 请尝试使用地图:
Map<String, MyObj> map = new HashMap<String, MyObj>() {{
put("hello", new MyObj("hello"));
put("world", new MyObj("world"));
}};
Then you can use: 然后你可以使用:
if (map.containsKey("hello"))
and to get the corresponding object: 并获得相应的对象:
MyObj o = map.get("hello"); // get() returns null if key not found
It is not equals of your object called when contains executes but the one from String class. 它不是在包含执行时调用的对象的等同,而是来自String类的对象。 And String implementation checks with instanceof whether the class is a String to perform String-like operations to determine the answer. 和String实现检查instanceof是否该类是一个String来执行类似String的操作来确定答案。 If object is not a String it will return false; 如果object不是String,则返回false;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.