文章还按照上篇文章的UML图来分析:
Set和HashSet
Set接口这一“派别”中,HashSet实现了Set接口,并且它还有一个子类LinkedHashSet。它们都根据对象的hashCode值来决定元素的存取位置,用equals方法来判断对象是否相等。所以重写对象equals方法时一定要根据实际场景重写hashCode方法。
比如要判断是否是同一个人,判断他的身份证号是否相同就可以了,所以Person类可以用下面的方式重写equals方法和hashCode方法:
public class Person{ private String idCard; private String name; @Override public boolean equals(Object o) { if (((Person)o).idCard.equals(idCard)){ return true; } return false; } }
虽然HashSet和LinkedHashSet都是根据对象的hashCode值来决定元素的存取位置,但是LinkedHashSet同时也使用链表来维护存入对象的次序,使对象看起来像是顺序插入的,所以当遍历LinkedHashSet时,将以对象插入的次序访问。两者的区别可以用下图来表示:
由于这种特性,使得LinkedHashSet迭代访问Set中元素时效率较HashSet高,但是增删元素的效率较低。
TreeSet
实现了SortedSet接口的TreeSet显著的特点就是排序,相同类型的元素进行排序才有意义,所以TreeSet中存放的元素必须是相同类型的,否则会报java.lang.ClassCastException异常。
之前没有太关注但它的功能很实用,这里多说两句~
TreeSet支持两种排序方式,自然排序和自定义排序。默认是自定义排序。但是TreeSet排序的前提是其中的元素要实现Comparable接口,或者有一个自定义的比较器。
比较常用的String、Date、Integer、Float、BigDecimal等类都实现了Comparable接口( 实现了它唯一的compareTo(T o) 方法 ),所以TreeSet对这些对象的排序都是默认的,而且是默认升序排列的。
自然排序示例:
添加实现了Comparable接口的元素:
Set ts=new TreeSet(); ts.add("helloworld"); ts.add("apple"); ts.add("danny"); for (Iterator iterator = ts.iterator(); iterator.hasNext();) { System.out.println(iterator.next()); }
输出结果
apple danny helloworld
如果TreeSet中需要添加自定义对象,则需要自定义一个比较器(实现Comparator接口)。
添加拥有比较器的元素
public class TreeSetTest{ @Test public void test(){ TreeSet ts=new TreeSet(new Person.PersonCompare()); Person p1=new Person("456","dannyhoo"); Person p2=new Person("123","dannySong"); ts.add(p1); ts.add(p2); for (Iterator iterator = ts.iterator(); iterator.hasNext();) { System.out.println(((Person)iterator.next()).getName()); } } } class Person{ private String idCard; private String name; public Person(String idCard,String name){ this.idCard=idCard; this.name=name; } public String getIdCard() { return idCard; } public void setIdCard(String idCard) { this.idCard = idCard; } public String getName() { return name; } public void setName(String name) { this.name = name; } static class PersonCompare implements Comparator{ @Override public int compare(Object o1, Object o2) { Person p1=(Person)o1; Person p2=(Person)o2; return p1.idCard.compareTo(p2.idCard);//按照身份证号排序 } } }
上面代码中的PersonCompare就是Person自己定义的比较器,需要实现Comparator接口并重写其compare接口,比较规则可以按照实际场景来定义。