Set
- Set接口:Set接口是Collection接口的子接口,其内部存储的元素,无序,无下标并且不可重复
- 增删改查方法与List一样
- Set实现类
- HashSet:根据hashCode与equals方法去除重复不保留任何顺序
- TreeSet:根据compareTo方法去除重复,对集合中的元素自动排序
HashSet
-
不允许null,不可重复,无序,线程不安全
-
HashSet:判断重复元素
- 调用对象的hashCode方法进行初步判断,如果hashCode值不同则表示没有重复可以将元素添加到HashSet集合中
- 由于hashCode是一个整数,不同的对象有可能拥有的相同的hashCode(发生了哈希碰撞),需要再调用equals方法判断内容是否相同,如果equals方法返回值为 true 则对象不会添加到集合中,反之则反
package com.qianfeng.xqc.day0305;
import java.util.HashSet;
import java.util.Set;
/**
* 声明Set<String> set = new HashSet<String>();
* 添加:set.add("jack");
* 获取:set的大小set.size();
* 删除:setPer.remove("jack");//set无序,不重复,删除根据里面元素来
* 查询:for(Iterator it = setPer.iterator();it.hasNext();) {
System.out.println(it.next());
}
* - 1:判断这两个内容的hash值是否相等;相等[有可能发生了哈希碰撞],不相等[不是同一个元素]
* - 2:如果发生了hash碰撞,就会调用equals方法,来确定这个对象里面的字段是否一致
* @author 淳
*
*/
public class DemoHashSet {
public static void main(String[] args) {
Set<String> set = new HashSet<String>();
set.add("jack");
set.add("jack");
set.add("xqc");
set.add("tom");
System.out.println(set.size());//3,jack重复当没看见
Set<Person> setPer = new HashSet<Person>();
Person p1 = new Person("jack",12);//如果p1和p2哈希值一样,则判定p1和p2重复
Person p2 = new Person("jack",12);
Person p3 = new Person("xqc",13);//如果p3和p4哈希值一样,重写equal方法不判定name,则判定p3和p4重复
Person p4 = new Person("rose",13);
Person p5 = new Person("tom",99);
setPer.add(p1);
setPer.add(p2);
setPer.add(p3);
setPer.add(p4);
setPer.add(p5);
System.out.println(setPer.size());
for(Person p : setPer) {
System.out.println(p);
}
}
}
class Person{
private String name;
private int age;
public Person() {}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
// return result;
return 0;
}
@Override
public boolean equals(Object obj) {
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 String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
TreeSet
-
TreeSet没有下标 ,不重复
-
TreeSet无序会对里面的元素进行排序 红黑树(左小右大的规则)
-
TreeSet 会进行排序,所以除了判断重复,一定要进行 顺序的比较和排列
- Comparable 接口:Person实现Comparable接口,重写compareTo判断两个元素是否相等并排序
- Comparator 比较器:自定义一个比较器,实现Comparator接口,重写compare方法进行比较排序
基本用法
package com.qianfeng.xqc.day0306;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
/**
* set没有下标 无序 不重复
* HashSet 不保证他会对里面的元素进行排序(自定一个对象,没有比较的方式方法)
* TreeSet 会对里面的元素进行排序 红黑树(左小右大的规则)
* @author 淳
*
*/
public class DemoTreeSet {
public static void main(String[] args) {
//实例化了一个set对象; TreeSet对象
Set<Integer> set = new TreeSet<Integer>();
//添加元素
set.add(5);
set.add(2);
set.add(0);
set.add(0); //这个0在保存的时候,发现是重复元素;所以不会保存到set集合里面去
//删除
set.remove(0);//根据元素删除
//查询; 1: 增强循环 2: 迭代器
for(int i : set) {
System.out.println(i);
}
for(Iterator<Integer> iterator = set.iterator();iterator.hasNext();) {//等于下方
System.out.println(iterator.next());
}
/*//1:获取迭代器对象
Iterator<Integer> iterator = set.iterator();
//2: hasNext()
while(iterator.hasNext()) {
//3: next()得到一个元素
int i = iterator.next();
System.out.println(i);
}
*/
}
}
Comparable 接口
package com.qianfeng.xqc.day0306;
import java.util.Set;
import java.util.TreeSet;
// 因为 HashSet他不需要排序; 只需要判断是否重复就行了;
// 我们 TreeSet 会进行排序,所以除了判断重复,一定要进行 顺序的比较和排列;
//为什么 HashSet 只需要重写 hashcode方法和equals就行了;
//而我们 TreeSet 需要自己去定义比较的方法?
/**
* HashSet他不需要排序; 只需要判断是否重复就行了;
* HashSet 只需要重写 hashcode方法和equals
* TreeSet 会进行排序,所以除了判断重复,一定要进行 顺序的比较和排列;
* TreeSet 需要自己去定义比较的方法
* @author 淳
*
*/
public class TestTreeSet {
public static void main(String[] args) {
//TreeSet一定会进行比较,Treeset要指定比较器,Person实现Comparable比较的接口
Set<Person> set = new TreeSet<Person>();
Person p1 = new Person("jack", 12);
Person p2 = new Person("rose", 12);
Person p3 = new Person("tom", 12);
Person p4 = new Person("jack", 12);
set.add(p1); //都是0
set.add(p2);
set.add(p3);
set.add(p4);
System.out.println(set.size());
for(Person p : set) {
System.out.println(p);
}
}
public static void test1() {
//TreeSet底层就是TreeMap的Key
Set<String> set = new TreeSet<String>();
//不存在让我们自己比较的过程
//加入到Treeset里面去,一定会进行比较
set.add("b");
set.add("c");
set.add("a");
set.add("h");
for(String s : set) {
System.out.println(s);
}
}
}
class Person implements Comparable{
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
private String name;
private int 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;
}
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
//TreeSet去进行比较,就是调用这个方法去比较;
//默认返回的都是0 ,代表相等;
@Override
public int compareTo(Object o) {
//根据姓名来决定这个两个元素是否相等;
//字符串,如何去比较:直接使用字符串自己写好的比较规则,去对name进行比较;
Person other = (Person)o;
return this.name.compareTo(other.name);
//根据年龄来比较呢?
// return this.age - other.age;
//-1 比原来的元素小 0 相等 1 比原来的元素大
// return 0;
}
}
Comparator 比较器
package com.qianfeng.xqc.day0306;
import java.util.Comparator;
import java.util.Set;
import java.util.TreeSet;
/**
* 写一个比较器MyComparator,传给我们Set去进行比较
* @author 淳
*
*/
public class TestTreeSetComparator {
public static void main(String[] args) {
//自己写一个比较器,传给我们Set去进行比较
Set<Student> set = new TreeSet<Student>(new MyComparator());
Student s1 = new Student("h", 12);
Student s2 = new Student("a", 12);
Student s3 = new Student("c", 12);
Student s4 = new Student("o", 12);
set.add(s1);
set.add(s2);
set.add(s3);
set.add(s4);
System.out.println(set.size());
for(Student s : set) {
System.out.println(s);
}
}
}
/**
* 自定义比较器; <Student> : 规定了,我们这个比较器,只能比较 Student
* @author 淳
*
*/
class MyComparator implements Comparator<Student>{
//重写他的比较方法
@Override
public int compare(Student o1, Student o2) {
//按照姓名来排序,和比较
return o1.getName().compareTo(o2.getName());
}
}
class Student{
private String name;
private int age;
@Override
public String toString() {
return "Student [name=" + name + ", 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;
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
比较TreeSet和HashSet
-
相同点
- 实现了 Set接口
- 不允许重复的元素
- 没有下标
- 无序[元素添加进去的顺序]
-
不同点
- 添加null元素:HashSet可以有一个Null(多了会覆盖掉); 但是TreeSet不行
- TreeSet里面的元素,一定会比高低(排序接口,比较器); HashSet只会去重(hashode equals)
- 底层实现不一样, TreeSet底层是树; HashSet底层是哈希表
package com.qianfeng.xqc.day0306;
import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
/**
* HashSet可以添加null元素
* TreeSet不可以添加null元素
* HashSet只能添加一个空元素(Set不允许重复的元素)
*/
public class DemoTreeSetANDHashSet {
public static void main(String[] args) {
Set<Integer> setHash = new HashSet<Integer>();
//添加
setHash.add(5);
setHash.add(2);
setHash.add(0);
setHash.add(0);
setHash.add(null);
for(Integer i : setHash) {//打印对象不拆箱就不会空指针
System.out.println(i);
}
/*
for(int i : setHash) {//打印的就是i对象
System.out.println(i);
}
// 从set里面取出来的是Integer;
// 你要把Integer赋值给int;
// 自动拆箱; obj.intValue()方法;
// set里面有一个null; null.intValue(); 导致空指针异常
*/
Set<Integer> setTree = new TreeSet<Integer>();
setTree.add(null);//TreeSet不能存放null
}
}