Set
常用方法:直接查看api
HashSet
元素唯一,但是无序(它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变)
案例:创建一个HashSet集合,添加元素(String元素),测试唯一性,无序性
package com.edu_01;
import java.util.HashSet;
import java.util.Set;
public class HashSetDemo {
public static void main(String[] args) {
//创建一个HashSet集合
HashSet<String> set = new HashSet<String>();
//给集合中添加元素
set.add("hello");
set.add("java");
set.add("world");
set.add("c++");
set.add("php");
set.add("hello");
//遍历集合
/* HashSet集合特点:
* 1.元素无序
* 2.元素唯一*/
for (String string : set) {
System.out.println(string);
}
//为什么在String类型中不用重写HashCode()和equals()方法
//因为String类型中,本来就包含了HashCode()和equals()方法
}
}
如何保证元素的唯一性的呢?
HashSet集合保证元素的唯一性和add()方法相关。
看add()方法的源码,看它的底层依赖什么内容?
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {…}
- 左边:e.hash == hash
- 比较对象的哈希值。
- 右边:((k = e.key) == key || key.equals(k))
- 左边:(k = e.key) == key
- 比较对象的地址值。
- 右边:key.equals(k)
- 比较的是对象的内容是否相同。默认情况下比较的是地址值
结论:
底层数据结构是哈希表。
哈希表依赖两个方法:hashCode()和equals()
执行流程:
首先判断哈希值是否相同,如果不同,就直接添加到集合。
如果相同,继续执行equals(),看其返回值,
如果是false,就直接添加到集合。
如果是true,说明元素重复不添加。
使用:
如果你看到哈希结构的集合,就要考虑可能需要重写这两个方法。
如果真要重写,自动生成即可。
哈希表结构:是一个元素为链表的数组结构
元素的哈希码值作为索引,元素本身的值作为数组的值存入到数组中
所以在存储过程中,先比较元素的哈希码值是否相同,如果不同,则直接添加,通过重写HashCode()方法,如果元素的哈希码值相同,在通过重写的equals()方法比较元素的地址值或者内容,如果有一个相同则该元素不能够存储
知识点
1.存储String类型的元素,说明元素无序且唯一
2.分析add()方法,保证唯一性的原理(底层依赖于hashCode()和equals()方法,保证了元素的唯一性)
3.存储自定义对象,如何保证元素的唯一性?(存储相同元素,发现无法保证元素的唯一性)
hashcode()方法保证了字符串的哈希码值相同,equals()保证了字符串的地址值和内容相同
public class HashSetDemo {
public static void main(String[] args) {
//创建一个HashSet集合
HashSet<String> set = new HashSet<String>();
//给集合中添加元素
set.add("hello");
set.add("java");
set.add("world");
set.add("c++");
set.add("php");
set.add("hello");
//遍历集合
/*HashSet集合特点:
* 1.元素无序
* 2.元素唯一*/
for (String string : set) {
System.out.println(string);
}
}
}
TreeSet
元素唯一,元素有序使用元素的自然顺序对元素进行排序,或者根据创建 set时提供的 Comparator进行排序(比较器排序),具体取决于使用的构造方法。
**底层算法:**二叉树
元素要求: 加入自定义JavaBean
二叉树结构存储数据的规则:
1.当存入第二个元素的时候会与第一个元素做减法,如果差值为负,说明你存的这个元素比之前的小往左边放
2.如差值为正,说明比之前存的值大,往右边放
3:如果值为0,说明相等则不存储
二叉树:根据compareTo()方法的返回值来确定要存入元素的安放位置。
案例演练:
案例1.创建集合存储Integer类型的元素(20,66,23,22,39,26,19,19,99),分析如何保证元素唯一性,以及排序的规则。
二叉树:根据compareTo()方法的返回值来确定要存入元素的安放位置。
import java.util.TreeSet;
public class TreeSetDemo {
public static void main(String[] args) {
/*
* 1.创建集合存储Integer类型的元素(20,66,23,22,39,26,19,19,99)
* 2.分析如何保证元素唯一性,以及排序的规则。
* 3.二叉树(首先讲解二叉树数据结构是怎么存入元素的,根据compareTo()方法的返回值来确定要存入元素的安放位置)*/
//创建一个TreeSet集合
/*TreeSet集合特点:
1.元素唯一 2.元素有序*/
TreeSet<Integer> ts = new TreeSet<Integer>();
//给集合中存储元素
//(20,66,23,22,39,26,19,19,99)
ts.add(20);
ts.add(66);
ts.add(23);
ts.add(22);
ts.add(39);
ts.add(26);
ts.add(19);
ts.add(19);
ts.add(99);
//遍历集合
for (Integer integer : ts) {
System.out.println(integer);
}
}
}
案例2.存储字符串并遍历(字母a-z排序)
import java.util.TreeSet;
public class TreeSetDemo2 {
public static void main(String[] args) {
//创建一个TreeSet集合
//当存入字符串的时候,按照字典顺序进行排序
TreeSet<String> ts = new TreeSet<String>();
//存入字符串
ts.add("linzhiling");
ts.add("amu");
ts.add("bigbang");
ts.add("guodegang");
//遍历集合
for (String string : ts) {
System.out.println(string);
}
}
}
3.存入学生对象(姓名,年龄),1.按年龄排序,2.姓名排序(自然排序实现Comparable接口,并重写comparaTo()
import java.util.TreeSet;
public class Student implements Comparable<Student>{
private String name;
private int age;
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
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 + "]";
}
//实现Comparable接口的同时必须实现这个比较法
@Override
public int compareTo(Student s) {
//就是写的是元素的比较规则,由你自己去动手写出
//按照学生的年龄进行排序
/* 两个对象进行比较:
* s
* this */
int num = this.age - s.age;
//判断年龄是否相同,如果相同比较姓名
/* 写这个比较规则的时候注意两点:
* 1.他有主要条件,先按照主要条件进行排序
* 2.如果主要条件相同,就需要你自己分析出来他的次要条件,再去按照次要条件进行比较 */
int num2 = num==0?this.name.compareTo(s.name):num;
return num2;
}
}