(二十六)Set系列集合

简介:

  • 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();
            }
        });
    }
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

晚风残照

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值