set 不包含等于其成员之一的项目?
set does not contain an item that equals one of its members?
所以根据the Java API,Set::contains
returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e))
所以...为什么即使集合只包含一个等于 creds
的元素,这种方法 returns 还是 false?
private boolean validate(Credentials creds){
Set<Credentials> acceptedUsers = getAcceptedUsers();
return acceptedUsers.contains(creds);
}
更具体地说,我插入了一些 printlns
private boolean validate(Credentials creds){
Set<Credentials> acceptedUsers = getAcceptedUsers();
System.out.print("accepted users: ");
System.out.println(acceptedUsers);
System.out.print("accessing user: ");
System.out.println(creds);
System.out.println("items are equal: " + acceptedUsers.stream().map(c -> c.equals(creds)).collect(Collectors.toSet()));
System.out.println("access ok: " + (acceptedUsers.contains(creds) ? "YES" : "NO"));
return acceptedUsers.contains(creds);
}
这就是它所说的:
accepted users: [[
foo
FCDE2B2EDBA56BF408601FB721FE9B5C338D10EE429EA04FAE5511B68FBF8FB9
]]
accessing user: [
foo
FCDE2B2EDBA56BF408601FB721FE9B5C338D10EE429EA04FAE5511B68FBF8FB9
]
items are equal: [true]
access ok: NO
getAcceptedUsers
目前returns一个虚拟集
private Set<Credentials> getAcceptedUsers(){
return new HashSet<Credentials>(){{add(new Credentials("foo","bar", false));}};
}
和Credentials
实现为
class Credentials{
final String username;
final String password;
public Credentials(String username, String password, boolean isPasswordHashed) {
this.username = username;
if(isPasswordHashed) this.password = password;
else {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
md.update(password.getBytes());
byte[] hash = md.digest();
this.password = (new HexBinaryAdapter()).marshal(hash);
}
}
@Override
public boolean equals(Object obj) {
if(obj == null) return false;
if(!(obj instanceof Credentials)) return false;
Credentials other = (Credentials)obj;
return this.username.equals(other.username) && this.password.equals(other.password);
}
@Override
public String toString() {
return String.format("[\n\t%s\n\t%s\n]", username,password);
}
}
实施 equals
方法还不够,您还必须实施 hashCode
。
喜欢你可以阅读here:
Returns the hash code value for this set. The hash code of a set is defined to be the sum of the hash codes of the elements in the set, where the hash code of a null element is defined to be zero. This ensures that s1.equals(s2) implies that s1.hashCode()==s2.hashCode() for any two sets s1 and s2, as required by the general contract of Object.hashCode().
如果您想使用 HashMap
或 HashSet
,您需要重写 hashCode()
方法,以便相等的对象具有相同的哈希码。例如:
@Override
public int hashCode() {
return Objects.hash(username, password);
}
所以根据the Java API,Set::contains
returns true if and only if this set contains an element e such that (o==null ? e==null : o.equals(e))
所以...为什么即使集合只包含一个等于 creds
的元素,这种方法 returns 还是 false?
private boolean validate(Credentials creds){
Set<Credentials> acceptedUsers = getAcceptedUsers();
return acceptedUsers.contains(creds);
}
更具体地说,我插入了一些 printlns
private boolean validate(Credentials creds){
Set<Credentials> acceptedUsers = getAcceptedUsers();
System.out.print("accepted users: ");
System.out.println(acceptedUsers);
System.out.print("accessing user: ");
System.out.println(creds);
System.out.println("items are equal: " + acceptedUsers.stream().map(c -> c.equals(creds)).collect(Collectors.toSet()));
System.out.println("access ok: " + (acceptedUsers.contains(creds) ? "YES" : "NO"));
return acceptedUsers.contains(creds);
}
这就是它所说的:
accepted users: [[
foo
FCDE2B2EDBA56BF408601FB721FE9B5C338D10EE429EA04FAE5511B68FBF8FB9
]]
accessing user: [
foo
FCDE2B2EDBA56BF408601FB721FE9B5C338D10EE429EA04FAE5511B68FBF8FB9
]
items are equal: [true]
access ok: NO
getAcceptedUsers
目前returns一个虚拟集
private Set<Credentials> getAcceptedUsers(){
return new HashSet<Credentials>(){{add(new Credentials("foo","bar", false));}};
}
和Credentials
实现为
class Credentials{
final String username;
final String password;
public Credentials(String username, String password, boolean isPasswordHashed) {
this.username = username;
if(isPasswordHashed) this.password = password;
else {
MessageDigest md;
try {
md = MessageDigest.getInstance("SHA-256");
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException(e);
}
md.update(password.getBytes());
byte[] hash = md.digest();
this.password = (new HexBinaryAdapter()).marshal(hash);
}
}
@Override
public boolean equals(Object obj) {
if(obj == null) return false;
if(!(obj instanceof Credentials)) return false;
Credentials other = (Credentials)obj;
return this.username.equals(other.username) && this.password.equals(other.password);
}
@Override
public String toString() {
return String.format("[\n\t%s\n\t%s\n]", username,password);
}
}
实施 equals
方法还不够,您还必须实施 hashCode
。
喜欢你可以阅读here:
Returns the hash code value for this set. The hash code of a set is defined to be the sum of the hash codes of the elements in the set, where the hash code of a null element is defined to be zero. This ensures that s1.equals(s2) implies that s1.hashCode()==s2.hashCode() for any two sets s1 and s2, as required by the general contract of Object.hashCode().
如果您想使用 HashMap
或 HashSet
,您需要重写 hashCode()
方法,以便相等的对象具有相同的哈希码。例如:
@Override
public int hashCode() {
return Objects.hash(username, password);
}