Java 容器(三) Set
1.这篇说到Set的用法,它的实现类有:
1)HashSet:不重复
2)TreeSet:不重复+主动排序
3)LinkedHashSet:不重复+保持插入时候的顺序
2.下面是具体用法:
package roadArchitectWeb.Test;
import java.util.Comparator;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.TreeSet;
class Student implements Comparable<Student>{
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(Integer id, String name) {
super();
this.id = id;
this.name = name;
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + "]";
}
@Override
public int hashCode() {
return this.id;
}
@Override
public boolean equals(Object obj) {
if(obj instanceof Student){
Student stu = (Student)obj;
if(stu.name == this.name)
return true;
}
return false;
}
@Override
public int compareTo(Student o) {
return this.id.compareTo(o.id);
}
}
class StudentComparator implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
return o2.getId().compareTo(o1.getId());
}
}
public class Test4 {
protected static Set<Student> hashSet = new HashSet<Student>();
protected static Set<Student> treeSetComparable = new TreeSet<Student>();
protected static Set<Student> treeSetComparator = new TreeSet<Student>(new StudentComparator());
protected static Set<Student> linkedHashSet = new LinkedHashSet<Student>();
public static void main(String[] args) {
hashSet.add(new Student(3,"sun"));
hashSet.add(new Student(1,"zhao"));
hashSet.add(new Student(2,"qian"));
System.out.println("hashSet:"+hashSet);
/*
*这里使用Comparable
*/
treeSetComparable.add(new Student(3,"sun"));
treeSetComparable.add(new Student(1,"zhao"));
treeSetComparable.add(new Student(2,"qian"));
System.out.println("treeSetComparable:"+treeSetComparable);
/*这里使用Comparator
*在讲Arrays的时候已经用了Comparator
*如果在treeset中使用的话,就在new Treeset时候传递一个 Comparator的实现类作为参数即可。
*/
treeSetComparator.add(new Student(3,"sun"));
treeSetComparator.add(new Student(1,"zhao"));
treeSetComparator.add(new Student(2,"qian"));
System.out.println("treeSetComparator:"+treeSetComparator);
linkedHashSet.add(new Student(3,"sun"));
linkedHashSet.add(new Student(1,"zhao"));
linkedHashSet.add(new Student(2,"qian"));
System.out.println("linkedHashSet:"+linkedHashSet);
}
}
3.三种实现方式都要重写hashcode和equals,为什么?
1)当我们想让对象不重复的进行保存的时候,我们会想到保存到Set里面,这是为什么?
因为Set的实现类提供了对一个对象进行不重复判断的方法,他会根据这个方法来判断两个对象是否一样,这个方法是equals;
2)既然有了equals方法会什么还要重写?
因为每个人认为的相同的标准不一样,equals方法默认方法如下:
public boolean equals(Object obj) {
return (this == obj);
}
它比较的是两个对象的地址是否一样,这样即使两个对象的内容完全一样,但是第二个是new的,也会认为不一样,这个时候如果我想把这两个对象当成一样的来看(这是正常人想法),那么就要重写equals,给他一个新的标准,比如比较两个对象的内容即可,不比较地址:
public boolean equals(Object obj) {
if(obj instanceof Student){
Student stu = (Student)obj;
if(stu.name == this.name && stu.id == this.id)
return true;
}
return false;
}
3)重写equals就可以了,为什么还要重写hashcode?
首先要了解hashcode是做什么的? 保存操作,当一个对象作为map的键的时候,Java怎么区分这个键,实际上它是通过键值来区分的,也就是说这个对象作为键,会自动产生一个键值,这个键值是怎么产生的? 就是通过hashcode
HashMap<Student, String> map = new HashMap<Student,String>();
Student student1 = new Student(1, "a");
Student student2 = new Student(2, "a");
Student student3 = new Student(3, "a");
map.put(student1,"student1");
map.put(student2,"student2");
map.put(student3,"student3");
那为什么要重写hashcode,因为默认的hashcode也指的是对象的地址,这样的话如果如果new一个对象,即使值完全一样也是无法取出的,因为地址是新开辟的:
去掉Student中的hashcode方法,然后执行:
HashMap<Student, String> map = new HashMap<Student,String>();
Student student1 = new Student(1, "a");
Student student2 = new Student(2, "a");
Student student3 = new Student(3, "a");
map.put(student1,"student1");
map.put(student2,"student2");
map.put(student3,"student3");
Student student4 = new Student(2, "a");
System.out.println("map:"+map.get(student4));
结果是:
map:null
怎么才能取出呢? 那就要改变hashcode生成方法,改变它的键值区分方式:
@Override
public int hashCode() {
return this.id;
}
再取出,就是:
map:student2
总的来说,使用map的时候,你不把这个对象作为键,就不可以不重写hashcode;但是Set是map实现的,它把对象作为键,那么用set的实现类的时候就要重写hashcode,以实现你想要的效果;
4.总结
1)Set和Map的实现类,其方式都是采用Map,所以都要重写hashcode方法;
2)继承Comparable接口的时候,说明有了排序方法,但只有在支持排序的集合里面才会主动排序,如treeSet,treeMap;Comparator也一样
3)List不支持插入的时候排序,所以list对Comparator和Comparable都支持是通过 Colections.sort,一个list参数代表Comparable排序,两个说明第二个参数是Comparator的实现类。Array同List.
4)linkedHashSet在迭代访问的时候更快,同时记录插入顺序;