Set集合
特点:无序,不重复。
遍历:foreach,迭代器
扩容:初始容量16,负载因子0.75,扩容增量1倍
HashSet:存储唯一元素允许为空,由HashMap支持,无序线程不安全
TreeSet:作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序,基于TreeMap实现
选择junit4,可以让方法单个实现(before,test)
before执行每个方法前先执行
public class HashSetTest {
public static void main(String[] args) {
Set books = new HashSet();
//分别向books集合中添加两个A对象、两个B对象、两个C对象
books.add(new A());
books.add(new A());
books.add(new B());
books.add(new B());
books.add(new C());
books.add(new C());
for (Object obj : books){
System.out.println(obj);
}//类A的equals()方法总是返回true,但没有重写其hashCode()方法
class A{
@Override
public boolean equals(Object obj){
return true;
}
}
//类B的hashCoded()方法总是返回1,但没有重写其equals()方法
class B{
@Override
public int hashCode(){
return 1;
}
}
//类C的hashCode()方法总是返回2,且重写了其equals()方法
class C{
@Override
public int hashCode(){
return 2;
}
@Override
public boolean equals(Object obj) {
return true;
}
}
上面程序中向books集合中分别添加了两个A对象、两个B对象和两个C对象,其中C类重写了equals()方法总是返回true,hashCode()方法总是返回2,这将导致HashSet把两个C对象当成同一个对象。
当把一个对象放入HashSet中时,如果需要重写该对象对应类的equals()方法,则也应该重写其hashCode()方法。其规则是:如果两个对象通过equals()方法比较返回true,这两个对象的hashCode值也应该相同。
如果两个对象通过equals()方法比较返回true,但这两个对象的hashCode()方法返回不同的hashCode值时,这将导致HashSet会把这两个对象保存在Hash表的不同位置,从而使两个对象都可以添加成功,这就与Set集合的规则有些出入了。
如果两个对象的hashCode()方法返回的hashCode值相同,但它们通过equals()方法比较返回false时将更麻烦:因为两个对象的hashCode值相同,HashSet将试图把它们保存在同一个位置,但又不行(否则将只剩下一个对象),所以实际上会在这个位置用链式结构来保存多个对象;而HashSet访问元素时也是根据元素的hashCode值来快速定位的,如果HashSet中两个以上的元素具有相同的hashCode值,将会导致性能下降。
当从HashSet中访问元素时,HashSet先计算该元素的hashCode值(也就是调用该对象的hashCode()方法的返回值),然后直接到该hashCode值对应的位置去取出该元素,这就是HashSet速度很快的原因。
重写hashCode()方法的基本规则
在程序运行过程中,同一个对象多次调用hashCode()方法应该返回相同的值。
当两个对象通过equals()方法比较返回true时,这两个对象的hashCode()方法应返回相等的值。
对象中用作equals()方法比较标准的Field,都应该用来计算hashCode值。
TreeSet类
TreeSet是SortedSet接口的实现类,正如SortedSet名字所暗示的,TreeSet可以确保集合元素处于排序状态。与HashSet集合想比,TreeSet还提供了如下几个额外的方法。
//如果TreeSet采用了定制排序,则该方法返回定制排序所使用的Comparator
//如果TreeSet采用了自然排序,则返回null
public Comparator<? super E> comparator() {
return m.comparator();
}
//返回集合中的第一个元素
public E first() {
return m.firstKey();
}
//返回集合中的最后一个元素
public E last() {
return m.lastKey();
}
//返回集合中位于指定元素之前的元素
//即小于指定元素的最大元素,参考元素不需要是TreeSet集合里的元素
public E lower(E e) {
return m.lowerKey(e);
}
//返回此Set的子集,由大于或等于fromElement的元素组成
public SortedSet<E> tailSet(E fromElement) {
return tailSet(fromElement, true);
}
创建一个学生类并实现编比较器接口
public class Student implements Comparable<Student>{
private Integer sid;
private String sname;
private int age;
public Student(Integer sid, String sname, int age) {
super();
this.sid = sid;
this.sname = sname;
this.age = age;
}
public Integer getSid() {
return sid;
}
public void setSid(Integer sid) {
this.sid = sid;
}
public String getSname() {
return sname;
}
public void setSname(String sname) {
this.sname = sname;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
需要在这个学生类中实现hashCode和equals方法
/*
*hashCode可以将学号名字努力转成唯一的数字,相对于身份证
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((sid == null) ? 0 : sid.hashCode());
result = prime * result + ((sname == null) ? 0 : sname.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (sid == null) {
if (other.sid != null)
return false;
} else if (!sid.equals(other.sid))
return false;
if (sname == null) {
if (other.sname != null)
return false;
} else if (!sname.equals(other.sname))
return false;
return true;//学号名字年龄都相等才是同一个学生
}
@Override
public String toString() {
return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";
}
/**
* 实现Comparable<Student>接口后需要重写的方法
* 根据年龄排序,年龄相同则比较学号,默认是升序
*/
@Override
public int compareTo(Student o) {
if(this.getAge()-o.getAge()==0) {
return this.getSid()-o.getSid();
}
return this.getAge() - o.getAge();
}
再使用ThreeSet
@Test
public void test04() {
TreeSet<Student> stu = new TreeSet<>();
stu.add(new Student(1,"zs", 18));
stu.add(new Student(1,"zs", 18));
stu.add(new Student(2,"ls", 19));
stu.add(new Student(4,"lihao", 10));
stu.add(new Student(7,"lihao", 18));
stu.add(new Student(5,"zengfanyan", 20));
stu.add(new Student(3,"we", 30));
for(Student s: stu) {
System.out.println(s);
}
}
运行输出结果: