Set集合以及HashSet、LinkedHashSet、TreeSet等讲解

时间:2021-09-02 15:26:12
 Set Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个 Set 集合中,则添加操作失败。 •Set 判断两个对象是否相同不是使用== 运算符,而是根据equals 方法
•HashSet 是 Set 接口的典型实现,大多数时候使用Set 集合时都使用这个实现类。•HashSet 按 Hash 算法来存储集合中的元素,因此具有很好的存取和查找性能。•HashSet 具有以下特点:    –不能保证元素的排列顺序    –HashSet不是线程安全的    –集合元素可以使 null•当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。•如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

•LinkedHashSet 是 HashSet 的子类•LinkedHashSet 集合根据元素的 hashCode 值来决定元素的存储位置,但它同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保存的LinkedHashSet性能插入性能略低于HashSet,但在迭代访问 Set 里的全部元素时有很好的性能。LinkedHashSet不允许集合元素重复
•TreeSet 是 SortedSet 接口的实现类,TreeSet可以确保集合元素处于排序状态TreeSet支持两种排序方法:自然排序和定制排序默认情况下,TreeSet采用自然排序
package com.hbut.test;


import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;


import com.hbut.domain.Person;


/**
 * Set(接口):放置的元素是按照哈希表来放的,元素是无序的;
 *    注意:1.放置元素时使用对象的equals方法判断的;
 *               2.可以放置null(null其实既不是类,也不是类型 )值,但是只能放一个;
 *    HashSet是Set接口的实现类,是非线程安全的,一般用的比较多,非线程安全可以转为线程安全的;
 *        LinkedHashSet:是HashSet的子类,对插入的数据是有序的,他的底层不仅有hash算法,还有链表维护,里面也不能有重复的元素。
 *         
 *    
 *
 */
public class TestSet {


public static void main(String[] args) {

Set set = new LinkedHashSet();//保证set的有序

set.add(null);
set.add(null);
System.out.println(set.size());

Person person =new Person();
Person person2 =new Person();


System.out.println(person.hashCode());    //注意:没有复写person的hashcode方法的话,那么两个对象是存在不一样的地方的。
System.out.println(person2.hashCode());


System.out.println(person.equals(person2));//注意:已经复写了person的equals方法了
System.out.println(person==person2);
set.add(person);//添加的是同一对象
set.add(person2);


System.out.println(set.size());


set.add(new Person("xx",21));  //并未覆写equals方法,所以是两个不同的对象,无法比较。如果复写了,那么就是一个了,去试试
set.add(new Person("xx",21));   
System.out.println(set.size());

set.add("hello");
Iterator it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}



}


}

//对于TreeSet的实验package com.hbut.test;


import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;


import com.hbut.domain.Student;
import com.hbut.exeception.StudentExeception;
import com.hbut.util.MyComparator;


public class TestTreeSet {


/**
* 1.如果使用treeSet的无参数构造器来创建对象,那么添加的对象必须实现Comparable接口,复写compareTo方法,不能放入null,不然会发生空指针异常;
* 2.不能传不是同一类对象,不然会发生类型转换异常ClassCastExeception异常
* 3.两个对象是按照Comparable的接口的comparaTo方法比较,是由TreeSet调用此方法

* (1).要么类实现Comparable接口,复写ComparaTo方法;
* (2).要么写一个比较器,Comparator 复写compare方法;(推荐这种,比较方法,可以直接使用)
*/
public static void main(String[] args) {

// Set st= new TreeSet();
//
// //st.add(null);
//
// st.add("BB");  //对放入的元素默认是按照自然顺序排序的,元素也是不可重复的,注意:还可以定制的;
// st.add("AA");
// st.add("CC");
//
// st.add("2");
// st.add("1");
// st.add("3");
//
//// int x=22;
//// st.add(x);
//
//
// for(Object obj :st){
//
// System.out.println(obj);
//
// }

Set st2= new TreeSet<>();
st2.add(new Student("BB",95));
st2.add(new Student("AA",95));//注意:此时的comparaTo返回的是true,是一样的分数,放不进去,与equals方法相背,需要注意,一般要求两个最好返回一样的值
st2.add(new Student("DD",91));
st2.add(new Student("CC",94));

for(Object obj :st2){

System.out.println(obj);

    }

Comparator ct = new MyComparator();

Comparator comparator = new Comparator() {//匿名内部类,这是一个比较器
@Override
public int compare(Object o1, Object o2){
if(o1 instanceof Student && o2 instanceof Student){
Student s1= (Student) o1;
Student s2= (Student) o2;
return s1.getScore()-s2.getScore();

}
else{

throw new ClassCastException("不是Student");

}

}
};


Set s3= new TreeSet<>(ct);
s3.add(new Student("yy",66));
s3.add(new Student("xx",65));
s3.add(new Student("zz",70));

System.out.println("--------用传入Comparator方法可行------------");
for(Object obj : s3){

System.out.println(obj);

    }

try {
test();//需要对异常进行处理。不然直接抛给虚拟机了
} catch (StudentExeception e) {

//System.out.println(e.getMsg());
e.printStackTrace();//复写了此方法的
}



}
public static void test() throws StudentExeception{  //声明异常,并没有处理

throw new StudentExeception("不是Student");//自定义的异常,抛出异常对象

}


}