简介:
- Set集合,基础自Collection。特征是插入无序,不可指定位置访问。
- Set集合的实现类可说是基于Map集合去写的。通过内部封装Map集合来实现的比如HashSet内部封装了HashMap。
- Set集合的数据库不能重复(== 或 eqauls)的元素
- Set集合的常用实现类有 HashSet TreeSet
1.Set集合实现类特点
HashSet:无序,不重复,无索引;
LinkedHashSet:有序,不重复,无索引;
①HashSet底层原理
HashSet集合底层采取哈希表存储的数据。
哈希表是一种对于增删改查数据性能都较好的结构。
1.哈希表
哈希值:是JDK根据对象的地址,按照某种规则算出来的int类型的数值。
Object类的API:
public int hashcode() 返回对象的哈希值
2.对象的哈希值特点
同一个对象多次调用hashCode()方法返回的哈希值是相同的。
默认情况下,不同对象的哈希值是不同的。
3.代码演示:
import java.util.*;
/**哈希值 同一对象的哈希值是相同的 不同对象的哈希值是不同的
* API:
*public int hashcode() 返回对象的哈希值
*/
public class Set_Demo {
public static void main(String[] args) {
Set<String> set = new HashSet<>();//经典代码 无序,不重复,无索引
Set<String> set1 = new LinkedHashSet<>();//有序 不重复 无索引
Set<String> set2 = new TreeSet<>();//排序 不重复 无索引
set.add("JAVA");
set.add("JAVA");
set.add("MySQL");
set.add("MYSQL");
set.add("HTML");
set.add("HTML");
System.out.println(set);
//哈希值
String name = "hertkvs";
System.out.println(name.hashCode());
String name1 = "hvammuras";
System.out.println(name1.hashCode());
}
}
6.Set集合的底层原理是什么样的?
JDK8以前,哈希表:底层使用数组+链表组成;
JDK8以后,哈希表:底层采用数组+链表+红黑树组成。
4.案例:Set集合去重复
需求:
创建一个存储学生对象的1集合,存储多个学生对象,实用程序实现在控制台遍历该集合,要求:学生对象的成员变量值相同,我们就认为是同一个对象。
分析:
①定义学生类,创建HashSet集合对象,创建学生对象;
②把学生添加到集合;
③在学生类中重写两个方法,hashCode()和equals(),自动生成即可;
④遍历集合(增强for)
学生类:
import java.util.Objects;
public class Student {
private String name;
private int age;
private char sex;
public Student(String name, int age, char sex) {
this.name = name;
this.age = age;
this.sex = sex;
}
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 char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
@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 && sex == student.sex && Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age, sex);
}
@Override
public String toString() {
return "Students{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
'}';
}
}
main类:
import java.util.HashSet;
import java.util.Set;
public class HashSet_Test {
public static void main(String[] args) {
Set<Student> sets = new HashSet<>();
Student s1 = new Student("无恙",10,'男');
Student s2 = new Student("山河",24,'男');
sets.add(s1);
sets.add(s2);
System.out.println(sets);
}
}
②LinkedHashSet
1.LinkedHashSet集合概述和特点
有序,不重复,无索引;
这里的有序指的是保证存储和取出的元素顺序一致;
2.原理:
底层数据结构依然是哈希表,只是每个元素又额外的多了一个双链表的机制记录存储的顺序。
③TreeSet
1.概述和特点
不重复,无索引,可排序
可排序:按照元素的大小默认升序(由小到大)排序。
TreeSet集合底层是基于红黑树的数据结构实现排序的,增删改查性能都较好。
注意:
TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序。
2.TreeSet集合默认的规则
对于数值类型:Integer,Double,官方默认按照大小进行升序排序。
对于字符串类型:默认按照首字符的编号升序排序。
对于自定义类型如Student对象,TreeSet无法直接排序。
④总结
1.如果希望元素可以重复,又有索引,索引查询要快?
用ArrayList集合,基于数组的。(用的最多)
2.如果希望元素可以重复,又有索引,增删首尾操作要快?
用LinkedList集合,基于链表的。
3.如果希望增删改查都快,但元素不重复,无序,无索引?
用HashSet集合,基于哈希表的。
4.如果希望增删改查都快,但元素不重复,有序,无索引?
用LinkedHashSet集合,基于哈希表和双链表的。
5.如果要对对象进行排序。
用TreeSet集合,基于红黑树,后续也可以用List集合实现排序。
⑤可变参数
1.概述:
可变参数用在形参中可以接收多个数据;
可变参数的格式: 数据类型....参数名称
2.可变参数的作用:
传输参数非常灵活,方便。可以不传输参数,可以传输1个或者多个,也可以传输一个数组;
可变参数在方法内部本质上就是一个数组;
3.代码演示:
import java.util.Arrays;
/*
可变参数
*/
public class Charge_Demo7 {
public static void main(String[] args) {
sum();//不传参数
sum(10);//传输一个参数
sum(11,22,33);//传输多个参数
sum(new int[]{11,22,33,44});//传输一个数组
}
private static void sum(int...nums) {
//注意:可变参数在方法内部其实就是一个数组
System.out.println("元素个数:"+nums.length);
System.out.println("元素内容"+ Arrays.toString(nums));
}
}
4.可变参数的注意事项:
1.一个形参列表中可变参数只能有一个;
2.可变参数必须放在形参列表的最后面;
⑥集合工具类Collections
1.概述:
①java.utils.Collections是集合工具类
②作用:Collections并不属于集合,是用来操作集合的工具类。
2.Collections常用API
3.代码演示:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**Collections API 不属于集合,用来操作集合的集合工具类
* public ststic boolean addAll(Collection<? super T> c,T... element) 批量添加元素
*public static void shuffle(list<?> list) 打乱集合顺序
* public static <T> void sort (list<T> list) 集合按照默认规则排序
* public static <T> void sort (list<T> list,comparator<? super T> c) 将集合中元素按指定规则排序
*/
public class Collections_Demo2 {
public static void main(String[] args) {
//1、批量添加元素
List<String> names = new ArrayList<>();
Collections.addAll(names,"楚风","皇莆嵩","太史慈");
System.out.println(names);
//2、打乱集合顺序、只能打乱list集合顺序
Collections.shuffle(names);
System.out.println(names);
//3、默认集合排序
List<Integer> sets =new ArrayList<>();//SHIFT+F6 快捷键:同步修改多个相同变量
Collections.addAll(sets,12,53,43,24);
System.out.println(sets);
Collections.sort(sets);
System.out.println(sets);
}
}
4.Collections排序相关API
使用范围:只能对于List集合的排序
排序方式一:
注意:
本方法不可以直接对自定义类型的List集合排序,除非自定义类型实现了比较规则Comparable接口。
排序方式二:
5.案例:斗地主游戏
需求:
在启动游戏房间的时候,提前准备好54张牌,完成洗牌,发牌,牌排序,逻辑。
分析:
①当系统启动的同时需要准备好数据的时候,就可以用静态代码块了。
②洗牌就是打乱牌的顺序。
③定义三个玩家,依次发出51张牌。
④给玩家的牌进行排序。
⑤输出每个玩家的牌数据。
牌类:
public class Card {
private String size;
private String color;
private int index;//牌的大小
public Card() {
}
public Card(String size, String color,int index) {
this.size = size;
this.color = color;
this.index = index;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
public String getSize() {
return size;
}
public void setSize(String size) {
this.size = size;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return size+color;
}
}
实现类:
import java.util.*;
import java.util.List;
public class Poker {
//定义静态集合存储牌
public static List<Card> allcards = new ArrayList<Card>();
//定义静态代码块初始化牌数据
static {
//点数确定 个数确定 类型确定 使用数组
String[] sizes = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"};
//定义花色 个数确定 类型确定 使用数组
String[] colors = {"♣","♠","♥","♦"};
//组合点数和花色
int index = 0;
for (String size : sizes) {
index++;
for (String color : colors) {
//封装成一个牌对象
Card c = new Card(size,color,index);
//存入集合
allcards.add(c);
}
}
//再添加大小王
Card c1 = new Card("","🃏",++index);
Card c2 = new Card("","🤡",++index);
Collections.addAll(allcards,c1,c2);
System.out.println("新牌: "+allcards);
}
public static void main(String[] args) {
// STOPSHIP: 2022/5/20
Collections.shuffle(allcards);
System.out.println("洗牌后:" + allcards);
//发牌(定义三个集合容器放置三个玩家)
List<Card> w1 = new ArrayList<>();
List<Card> w2 = new ArrayList<>();
List<Card> w3 = new ArrayList<>();
//开始发牌(剩余三张)
for (int i = 0; i < allcards.size()-3; i++) {
//先拿到当前牌对象
Card c = allcards.get(i);
if (i%3 == 0) {
//接牌
w1.add(c);
} else if (i%3==1) {
w2.add(c);
} else if (i%3==2) {
w3.add(c);
}
}
//拿最后三张牌
List<Card> lastTreeCards = allcards.subList(allcards.size()-3,allcards.size());
//给玩家的牌排序(从大到小)
sortCast(w1);
sortCast(w2);
sortCast(w3);
//输出玩家的牌
System.out.println("玩家一:"+w1);
System.out.println("玩家二:"+w2);
System.out.println("玩家三:"+w3);
System.out.println("最后三张底牌:"+lastTreeCards);
}
private static void sortCast(List<Card> cards) {
Collections.sort(cards, new Comparator<Card>() {
@Override
public int compare(Card o1, Card o2) {
//知道牌的大小,指定规则
return o1.getIndex()-o2.getIndex();
}
});
}
}