1.Set集合概述
Set是一个接口,与List集合类似,都需要通过实现类来对其进行操作。Set集合的特点如下。
a.不包含重复的元素。
b.没有带索引的方法,不能使用普通for循环遍历。
package Demo1;
import java.util.HashSet;
import java.util.Set;
/**
* @Description: TODO Set集合的基本应用
*/
public class Test1 {
public static void main(String[] args) {
// HashSet 不保证集合的迭代顺序,但是不重复
Set<String> set = new HashSet<>();
set.add("黄固");
set.add("欧阳锋");
set.add("段智兴");
set.add("洪七公");
set.add("欧阳锋"); //重复的元素添加不进去
//Set集合的读写顺序不一定一致
System.out.println(set);
}
}
2.Set集合常见方法说明
方法 | 解释 |
boolean add(E e) |
添加元素,但重复元素不会被添加成功
|
void clear() |
清空集合
|
boolean contains(Object o) |
判断
o
是否在集合中
|
Iterator<E> iterator() |
返回迭代器
|
boolean remove(Object o) |
删除集合中的
o
|
int size() |
返回
set
中元素的个数
|
boolean isEmpty() |
检测
set
是否为空,空返回
true
,否则返回
false
|
Object[] toArray() |
将
set
中的元素转换为数组返回
|
boolean containsAll(Collection<?> c) |
集合
c
中的元素是否在
set
中全部存在,是返回
true
,否则返回
false
|
boolean addAll(Collection<? extends E> c) |
将集合
c
中的元素添加到
set
中,可以达到去重的效果
|
TreeSet的使用案例:
package Demo6;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
public class TestSet {
public static void main(String[] args) {
Set<String> s = new TreeSet<>();
// add(key): 如果key不存在,则插入,返回ture
// 如果key存在,返回false
boolean isIn = s.add("apple");
s.add("orange");
s.add("peach");
s.add("banana");
System.out.println(s.size());
System.out.println(s);
isIn = s.add("apple");
// add(key): key如果是空,抛出空指针异常
//s.add(null);
// contains(key): 如果key存在,返回true,否则返回false
System.out.println(s.contains("apple"));
System.out.println(s.contains("watermelen"));
// remove(key): key存在,删除成功返回true
// key不存在,删除失败返回false
// key为空,抛出空指针异常
s.remove("apple");
System.out.println(s);
s.remove("watermelen");
System.out.println(s);
Iterator<String> it = s.iterator();
while(it.hasNext()){
System.out.print(it.next() + " ");
}
System.out.println();
}
}
3.Hash值
哈希值:是JDK根据对象的地址或者字符串或者数值计算出来的int类型的数值。 Object对象中就有一个方法可以获取对象的Hash值:public native int hashCode()。
对象的Hash值特点如下:
a.同一个对象多次调用hashCode()方法,得到的返回值是相同的。
b.默认情况下,不同对象的Hash值是不同的,但是可以通过重写hashCode()方法实现不同对象的Hash值相同。
通过hashCode方法查看Hash值:
package Demo1;
/**
* @Description: TODO 哈希值
*/
public class Test2 {
public static void main(String[] args) {
String str = new String("我是一个字符串");
System.out.println(str.hashCode());
System.out.println("我是一个字符串".hashCode());
System.out.println("我是一个字符串".hashCode());
System.out.println("================================");
System.out.println("我也是一个字符串".hashCode());
System.out.println("================================");
System.out.println(new Object().hashCode());
System.out.println(new Object().hashCode());
System.out.println(new Object().hashCode());
}
}
不同对象也可能具有相同的Hash值:
package Demo1;
import java.util.HashSet;
public class Test3 {
public static void main(String[] args) {
System.out.println("轷龚".hashCode());
System.out.println("辂鹅".hashCode());
System.out.println("输鰶".hashCode());
System.out.println("辎鳑".hashCode());
System.out.println("辇鶪".hashCode());
System.out.println("辌鴏".hashCode());
HashSet<String> str = new HashSet<>();
str.add("轷龚");
str.add("辇鶪");
//Hash值不同的两个对象肯定不是同一个对象
//但是即使Hash值相同,也不能确定一定是同一个对象
//不同的对象也可能具有相同的Hash值
}
}
4.哈希表
通过数组 + 链表的方式实现
构造方法数组16个元素,哈希值 % 16作为头节点位置选择
5.HashSet
HashSet集合是Set接口的实现类,其特点如下。
a.底层数据结构是Hash表。
b.对集合的迭代顺序不做任何保证,也就是说,不能保证存储和读取的顺序一致。
c.没有带索引的方法,也就是说,不能使用普通for循环对其进行遍历。
d.由于是Set集合,所以不存在重复的元素。
HashSet的去重原理是:先对比hashCode,如果相同,则再对比equals内容,这两个方法经常需要在子类中进行重写。
package Demo2;
import java.util.HashSet;
import java.util.Random;
import java.util.TreeSet;
/**
* @Description: TODO 双色球Set版
*/
public class Test1 {
public static void main(String[] args) {
Random ran = new Random();
int blueBall = ran.nextInt(16) + 1;
//HashSet<Integer> redBalls = new HashSet<>();
TreeSet<Integer> redBalls = new TreeSet<>(); // 有序的Set集合,逻辑顺序
while(redBalls.size() < 6) {
redBalls.add(ran.nextInt(33) + 1);
}
System.out.println("红球:" + redBalls + " | 蓝球:[" + blueBall + "]");
}
}
package Demo3;
import java.util.Objects;
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return age == student.age && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
package Demo3;
import java.util.HashSet;
/**
* @Description: TODO Set 集合存储学生类对象如何去重
*/
public class Test {
public static void main(String[] args) {
HashSet<Student> stuSet = new HashSet<>();
stuSet.add(new Student("Andy",19));
stuSet.add(new Student("Lucy",18));
stuSet.add(new Student("Jack",17));
stuSet.add(new Student("Andy",19));
for (Student stu : stuSet) {
System.out.println(stu);
}
}
}
6.LinkedHashSet
LinkedHashSet集合是Hash表和链表实现的Set接口,其特点如下。
a.具有可预测的迭代顺序。
b.通过链表保证元素有序,也就是说,元素的存储和读取顺序是一致的。
c.通过Hash表保证元素的唯一性,也就是说,没有重复的元素。
package Demo4;
import java.util.LinkedHashSet;
/**
* @Description: TODO LinkedHashSet 的特点 - 读写有序
*/
public class Test1 {
public static void main(String[] args) {
LinkedHashSet<String> set = new LinkedHashSet<>();
set.add("黄固");
set.add("欧阳锋");
set.add("段智兴");
set.add("洪七公");
set.add("王重阳");
System.out.println(set);
for (String str : set) {
System.out.println(str);
}
}
}
7.TreeSet
TreeSet集合是Set接口中的一个实现类,其特点如下。
a.元素有序,这里的“序”不是指存储和读取的顺序,而是指按照一定的规则进行排序,具体排序方式取决于实例化对象时的构造方法。
TreeSet():根据元素的自然顺序进行排序。
TreeSet(Comparator comparator):根据指定的比较器进行排序。
b.没有带索引的方法,不能使用普通for循环进行遍历。
c.由于是Set集合,所以不存在重复的元素。
package Demo5;
import java.util.TreeSet;
/**
* @Description: TODO TreeSet的基本用法
*/
public class Test1 {
public static void main(String[] args) {
TreeSet<Integer> ts = new TreeSet<>();
ts.add(5);
ts.add(2);
ts.add(1);
ts.add(3);
ts.add(6);
ts.add(4);
ts.add(8);
ts.add(7);
System.out.println(ts);
}
}
使用自定义排序规则(接口实现):
package Demo5;
/**
* @Description: TODO 学生类
*/
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Student o) {
//return 0; //0表示相等,后面传递进来的o对象就存储不进去
//return 9527; //大于0,表示o对象比当前的对象大,放到后面
//return -1314; //小于0,表示o对象比当前的对象小,放到前面
//根据年龄进行排序,如果年龄相同,就根据姓名字符串进行排序
int res = this.getAge() - o.getAge();
return 0 == res ? this.getName().compareTo(o.getName()) : res;
}
}
package Demo5;
import java.util.TreeSet;
/**
* @Description: TODO Student类对象存储到TreeSet集合当中
*/
public class Test2 {
public static void main(String[] args) {
TreeSet<Student> stuSet = new TreeSet<>();
stuSet.add(new Student("Andy",29));
stuSet.add(new Student("Jack",39));
stuSet.add(new Student("Lily",19));
stuSet.add(new Student("Tom",49));
stuSet.add(new Student("Lucy",19));
for (Student stu : stuSet) {
System.out.println(stu);
}
}
}