AbstractSet
ConcurrentHashMap
KeySetView
ConcurrentSkipListSet
CopyOnWriteArraySet
EnumSet
HashSet
JobStateReasons
LinkedHashSet
TreeSet
和List接口一样,Set接口也是Collection的子接口,因此,常用方法和Collection接口一样
同Collection的遍历方式一样,因为Set接口是Collection接口的子接口。
package com.taotao.set_;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* Create By 刘鸿涛
* 2022/1/6 20:14
*/
public class SetMethod {
public static void main(String[] args) {
//1.以Set 接口的实现类 HashSet 来讲解Set 接口的方法
//2.set 接口的实现类的对象(Set接口对象),不能存放重复的元素,可以添加一个null
//3.set 接口对象存放数据是无序(即添加的顺序和取出的顺序不一致)
//4.注意:取出的顺序虽然不是添加的顺序,但是他是固定的
Set set = new HashSet();
set.add("john");
set.add("lucy");
set.add("taotao");
set.add("taotao"); //重复
set.add(null);
set.add(null); //再次添加null
System.out.println(set);
//删除元素
set.remove(null);
//增强for
System.out.println("===========增强for==========");
for(Object o:set){
System.out.println(o);
}
//迭代器
System.out.println("===========迭代器============");
Iterator iterator = set.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
//普通for,没有索引,所以没有get,不能使用for
System.out.println("===========普通for============");
for (int i = 0; i < set.size(); i++) {
// System.out.println(set.get); //error
}
}
}
package com.taotao.set_;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
/**
* Create By 刘鸿涛
* 2022/1/6 20:18
*/
public class Test {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int arr[] = new int[(sc.nextInt())];
Set set = new HashSet();
for (int i = 0; i < arr.length; i++) {
arr[i] = sc.nextInt();
set.add(arr[i]);
}
System.out.println(set);
}
}
public HashSet(){
map = new HashMap();
}
package com.taotao.set_;
import java.util.HashSet;
import java.util.Set;
/**
* Create By 刘鸿涛
* 2022/1/7 2:33
*/
public class HashSet_ {
public static void main(String[] args) {
//解读
//1.构造器走的源码
/*
public HashSet(){
map = new HashMap<>();
}
*/
//2.HashSet 可以放null,但是不能有重复元素,并且取出顺序不保证与添加数据 顺序一致(否定)
Set hashSet = new HashSet();
hashSet.add(null);
hashSet.add(null);
System.out.println(hashSet);
}
}
package com.taotao.set_;
/**
* Create By 刘鸿涛
* 2022/1/7 14:49
*/
public class HashSetStructure { //Structure:结构
public static void main(String[] args) {
//模拟一个HashSet的底层 == HashMap的底层
//1.创建一个数组,数组的类型是 Node[]
//2.有些人,直接把 Node[] 数组称为 表table
Node[] table = new Node[16];
//3.创建节点
Node john = new Node("john",null);
table[2] = john;
Node jack = new Node("jack",null);
john.next = jack; //将jack 节点挂载到john
Node rose = new Node("rose",null);
jack.next = rose; //将rose 节点挂载到jack
Node lucy = new Node("lucy",null);
table[3] = lucy; //将 rose 节点挂载到jack
System.out.println(table);
}
}
class Node{ //结点,存储数据,可以指向下一个节点,从而形成链表
Object item; //存放数据
Node next; //指向下一个节点
public Node(Object item, Node next) {
this.item = item;
this.next = next;
}
@Override
public String toString() {
return "Node{" +
"item=" + item +
", next=" + next +
'}';
}
}
package com.taotao.set_;
import java.util.HashSet;
/**
* Create By 刘鸿涛
* 2022/1/7 15:49
*/
public class HashSetSource {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add("java"); //第一个add.java分析完毕
hashSet.add("php");
hashSet.add("java");
System.out.println(hashSet);
/*
HashSet 的源码解读
1.执行
public HashSet() {
map = new HashMap<>();
}
2.执行
public boolean add(E e) {
return map.put(e, PRESENT)==null; (static)PRESENT = new Object();
}
3.执行 put(),该方法会执行 hash(key) 得到key对应的hash值 算法 h = key.hashCode()) ^ (h >>> 16)
public V put(K key, V value) { //key = "java" value = PRESENT 共享
return putVal(hash(key), key, value, false, true);
}
4.执行 putVal
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
boolean evict) {
Node[] tab; Node p; int n, i;
//table 就是 HashMap 的一个数组,类型是 Node[]
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
//(1)根据key,得到hash 去计算该key应该存放到table表的哪个索引位置
//并把这个位置的对象,赋给 p
//(2)判断p 是否为null
//(2.1)如果p 为 null,表示还没存放元素,就创建一个Node (key="java",value=PRESENT)
//(2.2)就放在该位置 tab[i] = newNode(hash, key, value, null)
if ((p = tab[i = (n - 1) & hash]) == null)
tab[i] = newNode(hash, key, value, null);
else {
//一个开发技巧提示:在需要局部变量(辅助变量)时候,再创建
Node e; K k;
//如果当前索引位置对应的链表的第一个元素和准备添加的key的hash值一样
//并且满足 下面两个条件之一:
//(1)准备加入的key 和 p 指向的Node 节点的 key 是同一个对象
//(2) p 指向的 Node 节点的 key 的equals() 和准备加入的key比较后相同
//就不能加入
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
//再判断 p 是不是一颗红黑树
//如果是一颗红黑树,就调用putTreeVal,来进行添加
else if (p instanceof TreeNode)
e = ((TreeNode)p).putTreeVal(this, tab, hash, key, value);
else { //如果table对应索引位置,已经是一个链表,就使用for循环比较
//1.依次和该链表的每一个元素比较后,都不相同,则加入到该链表的最后
// 注意在把元素添加到链表后,立即判断 该链表是否已经达到8个结点
// ,就调用 treeifyBin() 对当前这个链表进行树化(红黑树)
// 注意,在转成红黑树时,要进行判断
// if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY(64))
// resize();
// 如果上面条件成立,先table扩容
// 只有上面条件不成立时,才进行转成红黑树
//2.依次和该链表的每一个元素比较过程中,如果有相同情况,就直接break
for (int binCount = 0; ; ++binCount) {
if ((e = p.next) == null) {
p.next = newNode(hash, key, value, null);
if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
*/
//第一个hashset.add("java") 分析完毕
}
}
package com.taotao.set_;
import java.util.HashSet;
/**
* Create By 刘鸿涛
* 2022/1/7 21:13
*/
public class HashSetIncrement {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
// for (int i = 0; i < 100; i++) {
// hashSet.add(i);
// }
//演示同一条链表上超出8个数据
for (int i = 0; i < 10; i++) {
hashSet.add(new Cat(i));
}
System.out.println(hashSet);
}
}
class Cat{
private int age;
public Cat(int age) {
this.age = age;
}
@Override
public int hashCode(){
return 100; //让hash值一样,就会得到一个链表
}
}
根据size++,如果超过size超过12,table会扩容
package com.taotao.set_;
import java.util.HashSet;
/**
* Create By 刘鸿涛
* 2022/1/7 21:13
*/
public class HashSetIncrement {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
// for (int i = 0; i < 100; i++) {
// hashSet.add(i);
// }
//演示table扩容细节
for (int i = 0; i < 7; i++) {
hashSet.add(new Cat(i));
}
for (int i = 0; i < 7; i++){ //当i走到5时,因为size超过临界值,所有table会扩容
hashSet.add(new A(i));
}
System.out.println(hashSet);
}
}
class Cat{
private int age;
public Cat(int age) {
this.age = age;
}
@Override
public int hashCode(){
return 100; //让hash值一样,就会得到一个链表
}
}
class A{
private int a;
public A(int a) {
this.a = a;
}
public int hashCode(){
return 200;
}
}
定义一个Employee类,该类包含:private成员属性name,age
创建3个Employee 放入 HashSet中
当 name 和 age的值相同时,认为是相同员工,不能添加到HashSet集合中
package com.taotao.set_;
import java.util.HashSet;
import java.util.Objects;
/**
* Create By 刘鸿涛
* 2022/1/8 3:27
*/
public class HashSetExercise {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new Employee("刘刘",50));
hashSet.add(new Employee("鸿鸿",50));
hashSet.add(new Employee("刘刘",50));
System.out.println(hashSet);
}
}
class Employee{
private String name;
private int age;
public Employee(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(){
this.age = age;
}
public String toString(){
return name + "\t" + age + "\n";
}
//如果name 和 age 值相同,则返回相同的hash值
//alt + insert => equals()and hashCode()
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee employee = (Employee) o;
return age == employee.age && name.equals(employee.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
package com.taotao.set_;
import java.util.HashSet;
import java.util.Objects;
/**
* Create By 刘鸿涛
* 2022/1/8 3:51
*/
public class HashSetExercise02 {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new Employee02("刘",10,new MyDate(1997,5,6))); //可以添加
hashSet.add(new Employee02("刘",20,new MyDate(1997,5,6))); //不能添加
hashSet.add(new Employee02("涛",10,new MyDate(1997,5,6))); //可以添加
System.out.println(hashSet);
}
}
class Employee02 {
private String name;
private double sal;
private MyDate birthday;
public Employee02(String name, double sal, MyDate birthday) {
this.name = name;
this.sal = sal;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSal() {
return sal;
}
public void setSal(double sal) {
this.sal = sal;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Employee02 that = (Employee02) o;
return name.equals(that.name) && birthday.equals(that.birthday);
}
@Override
public int hashCode() {
return Objects.hash(name, birthday);
}
@Override
public String toString() {
return "Employee02{" +
"name='" + name + '\'' +
", sal=" + sal +
", birthday=" + birthday +
'}';
}
}
class MyDate{
private int year;
private int month;
private int day;
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyDate myDate = (MyDate) o;
return year == myDate.year && month == myDate.month && day == myDate.day;
}
@Override
public int hashCode() {
return Objects.hash(year, month, day);
}
}
说明
package com.taotao.set_;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
/**
* Create By 刘鸿涛
* 2022/1/8 4:25
*/
public class LinkedHashSet_ {
public static void main(String[] args) {
Set set = new LinkedHashSet();
set.add(new String("AA"));
set.add(456);
set.add(456);
set.add(new Customer("刘",1001));
set.add("123");
set.add("taotao");
System.out.println(set);
//1.LinkedHashSet 加入顺序和取出元素/数据的顺序一致
//2.LinkedHashSet 底层维护的是一个LinkedHashMap (Map下的子类,HashMap下的子类)
//3.LinkedHashSet 底层结构 (数组 + 双向链表)
//4.添加第一次时,直接将 数组 table 扩容到 16 ,存放的结点类型是 LinkedHashMap$Entry
//5.数组是 HashMap$Node[] 存放的元素/数据是 LinkedHashMap$Entry类型(多态,继承)
/*
//继承关系是在内部类完成的。
static class Entry extends HashMap.Node{
Entry before,after;
Entry(int hash, K key, V value,Node next){
super(hash, key, value, next);
}
}
*/
}
}
class Customer{
private String name;
private int id;
public Customer(String name, int id) {
this.name = name;
this.id = id;
}
}
package com.taotao.set_;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.Set;
/**
* Create By 刘鸿涛
* 2022/1/8 5:14
*/
public class LinkedHashSetExercise {
public static void main(String[] args) {
Set set = new LinkedHashSet();
set.add(new Car("奔驰",50));
set.add(new Car("宝马",50));
set.add(new Car("奔驰",50));
System.out.println(set);
}
}
class Car{
private String name;
private int price;
public Car(String name, int price) {
this.name = name;
this.price = price;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Car car = (Car) o;
return price == car.price && name.equals(car.name);
}
@Override
public int hashCode() {
return Objects.hash(name, price);
}
@Override
public String toString() {
return "Car{" +
"name='" + name + '\'' +
", price=" + price +
'}';
}
}
TreeSet底层就是TreeMap
package com.taotao.set_;
import java.util.Comparator;
import java.util.TreeSet;
/**
* Create By 刘鸿涛
* 2022/1/9 18:50
*/
public class TreeSet_ {
public static void main(String[] args) {
// TreeSet treeSet = new TreeSet();
TreeSet treeSet = new TreeSet(new Comparator() { //Comparator有参构造器 + 匿名内部类
@Override
public int compare(Object o1, Object o2) {
//下面 调用String的 compareTo方法进行字符串大小比较,
// return ((String) o1).compareTo((String)o2);
//下面按照长度大小排序
return ((String)o1).length() - ((String)o2).length(); //注意,长度相同的数据加不进去
}
});
//添加数据
treeSet.add("jack");
treeSet.add("tom");
treeSet.add("taotao");
treeSet.add("a");
//默认根据字母升序
System.out.println(treeSet); //a,jack,taotao,tom
//添加的元素,按照字符串大小来排序
//1.使用TreeSet 提供的构造器,可以传入一个比较器
}
}