目录
来个class的定义:
public class Member {
private String id;
private String username;
private short age;
/**
* @return the id
*/
public String getId() {
return id;
}
/**
* @param id the id to set
*/
public void setId(String id) {
this.id = id;
}
/**
* @return the username
*/
public String getUsername() {
return username;
}
/**
* @param username the username to set
*/
public void setUsername(String username) {
this.username = username;
}
/**
* @return the age
*/
public short getAge() {
return age;
}
/**
* @param age the age to set
*/
public void setAge(short age) {
this.age = age;
}
public Member(String id, String username, short age) {
this.id = id;
this.username = username;
this.age = age;
}
/* (non-Javadoc)
* @see java.lang.Object#hashCode()
*/
@Override
public int hashCode() {
return Objects.hash(id, username);
}
/* (non-Javadoc)
* @see java.lang.Object#equals(java.lang.Object)
*/
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Member)) {
return false;
}
Member other = (Member) obj;
return this.id.equals(other.id);
}
}
简单的小demo(error):
public static void main(String[] args) {
// 定义一个比较器先
Comparator<Member> c = new Comparator<Member>() {
@Override
public int compare(Member o1, Member o2) {
return o1.getAge() > o2.getAge() ? 1 : -1;
}
};
Set<Member> set = new TreeSet<Member>(c);
Member o = new Member("1001","t",(short) 21);
set.add(new Member("1002","t",(short) 22));
set.add(new Member("1003","t",(short) 23));
set.add(o);
System.out.println(set.size());
System.out.println(set.contains(o));
}
运行结果输出:
size:3
false
嗯嗯嗯??,size为3可以理解,但是这个false就有点尴尬了,同一个对象明明已经加到了容器中,你和我说没有??
分析:
难道和比较器的compare()方法有关??是滴,你的猜测煤油错,真相只有一个!
其实对于Tree数据结构的集合判断元素唯一性的方式:就是根据compare()的返回结果是否是0,是0,就是相同元素。
相信大家应该都知道TreeSet对象它里边使用的就是TreeMap的key来存储对象,
打个断点来一探究竟:
将id为1001的member对象作为参数调用contains()方法,
跟着断点进入TreeSet的contains()方法里边,可以看到它其实调用的就是一个Map对象的containsKey()方法,
继续跟进到TreeMap里边,它又调用了getEntry()方法:
外部比较器不为空,继续调用getEntryUsingComparator(key)方法 ,
root的值是存储到集合中id为1002的member对象,然后开始调用比较器的compare方法来对两个对象进行比较,
比较返回的结果是-1,小于0,把p的左边节点给p来引用,通过debug可以看到左节点就是id为1001的节点,
继续while循环,调用比较方法,返回还是-1(21不大于21),左节点为null,赋值给p,p为null,循环结束,返回null,
getEntry(key)!=null;表达式不成立,返回值false,不包含这个key,最后的输出结果为false;
正确打开方式:正确实现compare方法
Comparator<Member> c2 = new Comparator<Member>() {
@Override
public int compare(Member o1, Member o2) {
int j1 = o1.getUsername().compareTo(o2.getUsername());
int j2 = o1.getId().compareTo(o2.getId());
return j1 == 0 ? j2 : j1;
}
};
嗯,一切都是那么的安逸!!
写的是啰唆了点,也可以看看大佬的。
一个传送门:Java Map的正确使用方式