四、Set的使用
4.1 主要实现类和方法
- 主要实现类就是:HashSet
- 常用方法:Set接口中声明的方法都是Collection接口声明过的。HashSet能使用的就是Collection中定义的方法。
@Test
public void test1(){
Set set = new HashSet();
set.add(223);
set.add(new String("AA"));
set.add("CC");
set.add(223);
set.add(new String("AA"));
set.add(new Person("Tom",12));
set.add(new Person("Tom",12));
set.add(null);
for(Object obj : set){
System.out.println(obj);
}
}
4.2 Set的特性:无序性、不可重复性
① 无序性:不等同于随机性!元素在底层储存的位置不是像数组一样是依次紧密排列的,而是参考其hashCode值决定的存储位置。理解为无序性
② 不可重复性:根据对象的equals()进行判断。如果返回true,则添加失败。保证了不可重复性。
4.3 向HashSet中添加数据的过程
如何将元素添加到HashSet中的呢?
* 前提:HashSet底层也是使用数组+链表+(jdk8:红黑树)存储
* ① 将元素e1添加到HashSet中,首先调用e1所在类的hashCode(),获取e1对象的哈希值。
* ② 此哈希值,经过某种算法以后,获取其在HashSet底层数组中的存放位置。
* ③ 如果此位置上,没有其他任何元素,则e1添加成功 --->情况1
* 如果此位置上,已经存在某个或某几个元素e2,则继续判断。
* ④ 比较e1和e2的哈希值,如果两个哈希值不相同。则e1添加成功。 --->情况2
* 比较e1和e2的哈希值,如果两个哈希值相同,则调用e1所在类的equals()方法
* ⑤ equals()方法返回false,则e1添加成功。 --->情况3
* equals()方法返回true,则e1添加失败。
*
* 情况1:将e1直接保存在数组的指定位置
* 情况2、情况3:此时e1与现有索引位置上的元素,以链表的方式进行保存。
* > jdk7:新的元素e1方法到数组中,指向原有的元素
* > jdk8:已有的元素的末尾指向新的元素e1.
* 总结:"七上八下"
4.4 向HashSet中添加的元素所在类的要求
1. 针对于HashSet或者LinkedHashSet来说,如果多个对象需要存储到上述两个Set中时,为了保证不可重复性,
* 必须要求对象所属的类要重写hashCode()和equals()(重点)
2. 重写hashCode()和equals()要保证一致性!相等的对象必须具有相等的散列码
4.5 Set的不同实现类的对比
|-----Collection:存储一个一个的数据
* |-----Set:存储无序的、不可重复的数据: 高中的集合
* |-----HashSet:是Set的主要实现类;线程不安全的;可以存储null值
|-----LinkedHashSet:是HashSet的子类;在添加数据之外,还通过一对指针记录先后添加 的顺序,使得遍历Set元素时,较HashSet效率更高。
|-----TreeSet:可以按照添加的元素的指定的属性的大小进行遍历;底层使用的是红黑树(排序二 叉树的一种)
4.6 LinkedHashSet的测试 (了解)
@Test
public void test2(){
Set set = new LinkedHashSet();
set.add(223);
set.add(new String("AA"));
set.add("CC");
set.add(223);
set.add(new String("AA"));
set.add(new Person("Tom",12));
set.add(new Person("Tom",12));
set.add(null);
for(Object obj : set){
System.out.println(obj);
}
}
4.7 TreeSet添加数据的情况 (了解)
//1. TreeSet可以按照添加的元素的指定的属性的大小进行遍历;
// 排序的方式有:自然排序,定制排序
//2. TreeSet底层使用的是红黑树(排序二叉树的一种)
//3. 要求:向TreeSet中添加的元素必须是同一个类型的对象。
//4. 说明:TreeSet中不能存放相同的元素。判断的标准不再是元素所在类的hashCode()和equals()了。而是按照自然
// 排序或定制排序中重写的compareTo()或compare()进行比较。
- 自然排序
举例1:
@Test
public void test1(){
TreeSet set = new TreeSet();
set.add("CC");
set.add("MM");
set.add("GG");
set.add("TT");
set.add("JJ");
set.add("KK");
// set.add(123);//报ClassCastException
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
举例2:
@Test
public void test2(){
TreeSet set = new TreeSet();
Person p1 = new Person("Tom",12);
Person p2 = new Person("Jim",32);
Person p3 = new Person("Jerry",26);
Person p4 = new Person("Mike",43);
Person p5 = new Person("Lily",26);
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
set.add(p5);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
其中,Person类定义如下:
public class Person implements Comparable{
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
/*
@Override
public int hashCode() { //return age + name.hashCode();
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
System.out.println("Person equals....");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
*/
//先按照年龄从小到大排列,再按照姓名从小到大排
@Override
public int compareTo(Object o) {
if(o instanceof Person){
Person p = (Person)o;
int value = this.age - p.age;
if(value != 0){
return value;
}else{
return this.name.compareTo(p.name);
}
}
throw new RuntimeException("输入的类型不匹配");
}
}
- 定制排序
@Test
public void test3(){
Comparator com = new Comparator(){
@Override
public int compare(Object o1, Object o2) {//o1,o2应该为Person的实例
if(o1 instanceof Person && o2 instanceof Person){
Person p1 = (Person)o1;
Person p2 = (Person)o2;
return -p1.getName().compareTo(p2.getName());
}
return 0;
}
};
TreeSet set = new TreeSet(com);
Person p1 = new Person("Tom",12);
Person p2 = new Person("Jim",32);
Person p3 = new Person("Jerry",26);
Person p4 = new Person("Mike",43);
Person p5 = new Person("Lily",26);
set.add(p1);
set.add(p2);
set.add(p3);
set.add(p4);
set.add(p5);
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}