Java基础学习之Set(18-2)

1. Set

1.1 Set集合的特点

  • 不包含重复元素的集合
  • 没有带索引的方法,所以不能使用普通for循环遍历
  • 是一个接口,不能直接实例化
package Java18.Set;


//HashSet<E>对集合的迭代次序不作任何保证
import java.util.HashSet;
import java.util.Set;

public class Setdemo {
    public static void main(String[] args) {
        Set<String> set = new HashSet<String>();

        set.add("hello");
        set.add("world");
        set.add("java");
        //不包含重复元素
        set.add("world");

        //遍历
        for(String s : set){
            System.out.println(s);
        }
    }

1.2 哈希值

哈希值:是JDK根据对象的地址或者字符串或者数字算出来的int类型的数值
Object类中有一个方法可以获取对象的哈希值

  • public int hashCode():返回对象的哈希码值

对象的哈希值特点

  • 同一个对象多次调用hashCode()方法返回的哈希值是相同的
  • 默认情况下,不同对象的哈希值是不同的。而重写hashCode()方法,可以实现让不同对象的哈希值相同。
package Java18.Set;

public class hashdemo {
    public static void main(String[] args) {
        //创建学生对象
        Student s = new Student("lyy",24);

        //同一个对象多次调用hashCode()方法返回的哈希值相同
        System.out.println(s.hashCode());//356573597
        System.out.println(s.hashCode());

        //默认情况下不同对象的哈希值是不一样的
        //通过方法重写可以实现不同对象的哈希值是相同的
        Student s2 = new Student("lyy",24);
        System.out.println(s2.hashCode());//1735600054
        System.out.println("----------");

        System.out.println("hello".hashCode());//99162322
        System.out.println("world".hashCode());//113318802
        System.out.println("world".hashCode());//113318802
        System.out.println("-------------------------");


        System.out.println("重地".hashCode());//1179395
        System.out.println("通话".hashCode());//1179395
    }
}

1.3 HashSet集合概述和特点

HashSet集合特点

  • 底层数据结构为哈希表
  • 对集合的迭代次序不作任何保证,也就是说不保证存储和取出的元素顺序一致
  • 没有带索引的方法,不能使用普通for循环遍历
  • 由于是Set集合,所以是不包含重复元素的集合
package Java18.Set;

import java.util.HashSet;
import java.util.Iterator;

public class demo2 {
    public static void main(String[] args) {
        HashSet<String> hash = new HashSet<String>();

        hash.add("l");
        hash.add("w");
        hash.add("d");
        hash.add("q");

        //遍历
        Iterator<String> it = hash.iterator();
        while(it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("------------");
        for (String s : hash){
            System.out.println(s);
        }

    }
}

1.3 HashSet集合保证元素唯一性源码分析

在这里插入图片描述

HashSet<String> hash = new HashSet<String>();

hash.add("l");
hash.add("w");
hash.add("d");
hash.add("q");
-----------------------------------------------
//调用add方法将元素存储进hashSet,add方法中调用put方法,其中e为传入的元素
public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}
//元素参数对于key,其中hash(key)表示元素的哈希值,然后在put方法中调用putVal方法
public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

//利用hashCode()方法获取key的哈希值
static final int hash(Object key) {
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}



//hash和元素的hashCode()方法相关
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; Node<K,V> p; int n, i;
    //如果哈希表未初始化,就对其进行初始化
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;
    //根据对象的hash值计算对象的存储位置,如果该位置没有元素就存储元素
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        /*
            存入的元素和以前的元素比较哈希值
                如果哈希值不同,会继续向下执行把元素添加到集合
                如果哈希值相同,会调用对象的equals方法来进行比较
                    如果返回false,会继续向下执行把元素添加到集合
                    如果返回true,说明元素重复不存储
        */
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            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;
}

1.4 HashSet 集合存储学生对象并遍历

学生类,在该类中重写hashCode和equal方法,使得成员变量相同的学生认为是同一个变量

package Java18.Set;

public class Student {
    private String name;
    private int age;

    public Student(){
    }

    public Student(String name, int age){
        this.name = name;
        this.age = age;
    }

    public void setName(String name){
        this.name = name;
    }

    public void setAge(int age){
        this.age = age;
    }

    public String getName(){
        return name;
    }

    public int getAge(){
        return age;
    }

    //重写hashCode和equal方法


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

        if (age != student.age) return false;
        return name != null ? name.equals(student.name) : student.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}
package Java18.Set;

import java.util.HashSet;
import java.util.Iterator;

public class HashsetDemo {
    public static void main(String[] args) {
        HashSet<Student> ha = new HashSet<Student>();

        //创建学生对象
        Student s1 = new Student("lyy",23);
        Student s2 = new Student("lyq",24);
        Student s3 = new Student("sss",43);
        Student s4 = new Student("lyy",23);

        //集合中添加元素
        ha.add(s1);
        ha.add(s2);
        ha.add(s3);
        ha.add(s4);

        //遍历
        Iterator<Student> it = ha.iterator();
        while(it.hasNext()){
            Student s = it.next();
            System.out.println(s.getName()+","+s.getAge());
        }
        System.out.println("---------------");

        for(Student s : ha){
            System.out.println(s.getName()+","+s.getAge());
        }

    }
}

1.5 LinkedHashSet 集合概述和特点

  • 哈希表和链表实现了Set接口,具有可预测的迭代次序。
  • 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
  • 由哈希表保证元素唯一,也就是说没有重复的元素

这种实现不同于HashSet,它维持于所有条目的运行双向链表。

练习:存储字符串并遍历

package Java18.Set;

import java.util.Iterator;
import java.util.LinkedHashSet;

public class LinkedHashSetdemo {
    public static void main(String[] args) {
        LinkedHashSet<String> lhs = new LinkedHashSet<String>();

        //添加元素
        lhs.add("lll");
        lhs.add("yyy");
        lhs.add("qqq");

        lhs.add("yyy");

        //遍历
        //实现set接口 可以调用Iterator迭代器
        Iterator<String> it = lhs.iterator();
        while(it.hasNext()){
            String s = it.next();
            System.out.println(s);
        }
        System.out.println("---------------");
        //增强for
        for(String s : lhs){
            System.out.println(s);
        }

    }
}

1.6 TreeSet 集合概述和特点

TreeSet 集合的特点

  • 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体的排序方式取决于构造方法
    TreeSet ():根据元素的自然顺序进行排序
    TreeSet (Comparator , comparator):根据指定的比较器进行排序
  • 没有索引的方法,不能使用普通for循环遍历,可以使用增强for和迭代器进行遍历

联系:存储整数并遍历

package Java18.Set;

import java.util.Iterator;
import java.util.TreeSet;

public class TreeSetdemo {
    public static void main(String[] args) {
        TreeSet<Integer> Tr = new TreeSet<Integer>();

        //集合添加元素
        Tr.add(1);
        Tr.add(2);
        Tr.add(3);
        Tr.add(7);
        Tr.add(5);

        //遍历
        //迭代器Iterator方法
        Iterator<Integer> it = Tr.iterator();
        while(it.hasNext()){
            int i = it.next();
            System.out.println(i);
        }
        System.out.println("---------------");

        //增强for
        for(int i : Tr){
            System.out.println(i);
        }
    }
}

输出结果会按照整数数据进行排序输出
在这里插入图片描述

1.7 自然排序 Comparable的使用

  • 存储学生对象并遍历,创建TreeSet 集合使用无参构造方法
  • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

学生类及CompareTo方法的重写

package Java18.Set.Treeset;

public class Student implements Comparable<Student>{
    private int age;
    private String name;

    public Student(){
    }

    public Student(String name,int age){
        this.name = name;
        this.age = age;
    }

    public void setName(String name){
        this.name = name;
    }

    public void setAge(int age){
        this.age = age;
    }

    public String getName(){
        return name;
    }

    public int getAge(){
        return age;
    }

    //重写Comparable里面的方法

    @Override
    public int compareTo(Student s) {
//        return 0;
//        return 1;
//        return -1;
        //按照年龄从小到大排序
        int num = this.age - s.age;
        //年龄相同时,按照姓名的字母排序
        int num2 = num==0?this.name.compareTo(s.name):num;
        return num2;

    }
}

学生类调用及排序

package Java18.Set.Treeset;

import java.util.TreeSet;

public class Treesetdemo2 {
    public static void main(String[] args) {
        TreeSet<Student> ts = new TreeSet<Student>();

        //创建学生对象
        Student s1 = new Student("lll",22);
        Student s2 = new Student("sss",23);
        Student s3 = new Student("eee",22);
        Student s4 = new Student("qqq",19);

        //添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);

        //遍历
        for(Student s : ts){
            System.out.println(s.getName()+","+s.getAge());
        }
    }
}

1.7 比较器Comparatot的使用

  • 存储学生对象并遍历,创建TreeSet 集合使用无参构造方法
  • 要求:按照年龄从小到大排序,年龄相同时,按照姓名的字母顺序排序

学生类

package Java18.Set.TreeSet2;

public class Student {

        private String name;
        private int age;

        public Student(){
        }

        public Student(String name, int age){
            this.name = name;
            this.age = age;
        }

        public void setName(String name){
            this.name = name;
        }

        public void setAge(int age){
            this.age = age;
        }

        public String getName(){
            return name;
        }

        public int getAge(){
            return age;
        }
}

测试类

package Java18.Set.TreeSet2;

import java.util.Comparator;
import java.util.TreeSet;

public class Treesetdemo1 {
    public static void main(String[] args) {
        //创建集合对象
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getAge() - s2.getAge();
                int num2 = num==0 ? s1.getName().compareTo(s2.getName()) : num;
                return num2;
            }
        });

        //创建学生对象
        Student s1 = new Student("lll", 22);
        Student s2 = new Student("sss", 23);
        Student s3 = new Student("eee", 22);
        Student s4 = new Student("qqq", 19);

        //添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);

        //遍历
        for (Student s : ts) {
            System.out.println(s.getName() + "," + s.getAge());

        }
    }
}
  • 用TreeSet集合存储自定义对象,带参构造方法使用的是比较器排序对元素进行排序的
  • 比较器排序,就是让集合构造方法接收Comparator的实现类对象,重写Comparator(To 1 ,T o2)方法

1.8 案例:学生成绩排序

两种方法:

  • 自然排序Comparable的使用,学生类中重写CompareTo方法
package Java18.Set.Treeset3;

public class Student implements Comparable<Student> {
    private String name;
    private int ma;
    private int ch;

    public Student(){
    }

    public Student(String name,int ma,int ch){
        this.name = name;
        this.ma = ma;
        this.ch = ch;
    }

    public void setName(String name){
        this.name = name;
    }
    public void setMa(int ma){
        this.ma = ma;
    }
    public  void  setCh(int ch){
        this.ch = ch;
    }

    public String getName(){
        return name;
    }
    public int getMa(){
        return ma;
    }
    public int getCh(){
        return ch;
    }

    @Override
    public int compareTo(Student s) {
        //先按总成绩排序
        int num = s.ma+s.ch-this.ma-this.ch;
        //若成绩相同,先比较语文成绩,若相同则按名字排序
        int num2 = num==0?s.ch-this.ch:num;
        int num3 = num2 == 0?s.name.compareTo(this.name):num2;
        return num3;
    }
}
package Java18.Set.Treeset3;

import java.util.TreeSet;

public class demo {
    public static void main(String[] args) {
        //创建集合
        TreeSet<Student> ts = new TreeSet<Student>();

        //创建学生对象
        Student s1 = new Student("lyy",93,96);
        Student s2 = new Student("lyq",95,97);
        Student s3 = new Student("dqd",90,93);
        Student s4 = new Student("hsy",85,91);
        Student s5 = new Student("dst",91,85);

        //集合添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);

        //遍历并按成绩排序成绩相同则按姓名
        for(Student s : ts){
            System.out.println(s.getName()+","+s.getCh()+","+s.getMa());
        }
    }
}

  • 比较器Comparatot的使用

学生类

package Java18.Set.Treeset3;

//比较器的使用

public class Student2 {
    private String name;
    private int ma;
    private int ch;

    public Student2(){
    }

    public Student2(String name, int ma, int ch) {
        this.name = name;
        this.ma = ma;
        this.ch = ch;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getMa() {
        return ma;
    }

    public void setMa(int ma) {
        this.ma = ma;
    }

    public int getCh() {
        return ch;
    }

    public void setCh(int ch) {
        this.ch = ch;
    }

    //定义一个求总分的方法
    public int getSum(){
        return this.ch+this.ma;
    }
}

测试类,使用局部内部类重写compare方法

package Java18.Set.Treeset3;

//比较器的使用

import java.util.Comparator;
import java.util.TreeSet;

public class demo2 {
    public static void main(String[] args) {
        //创建集合对象,调用局部内部类
        TreeSet<Student2> ts = new TreeSet<Student2>(new Comparator<Student2>() {
            @Override
            public int compare(Student2 s1, Student2 s2) {
                //比较总分
//                int num = s2.getCh()+s2.getMa()-s1.getCh()-s1.getMa();
                int num = s2.getSum()-s1.getSum();
                //若总分相同,比较语文成绩,语文成绩相同比较名字进行排序
                int num2 = num==0?s1.getCh()-s2.getCh():num;
                int num3 = num2==0?s1.getName().compareTo(s2.getName()):num;
                return num3;
            }
        });
        //创建学生对象
        Student2 s1 = new Student2("lyy",93,96);
        Student2 s2 = new Student2("lyq",95,97);
        Student2 s3 = new Student2("dqd",90,93);
        Student2 s4 = new Student2("hsy",85,91);
        Student2 s5 = new Student2("dst",91,85);

        //集合添加元素
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);

        //遍历并按成绩排序成绩相同则按姓名
        for(Student2 s : ts){
            System.out.println(s.getName()+","+s.getCh()+","+s.getMa()+","+s.getSum());
        }
    }
}

//获取10个1-20之间的随机数,要求随机数不能重复,并在控制台输出
package Java18.Set.TreeSet4;

import java.util.HashSet;
import java.util.Random;
import java.util.Set;

public class demo {
    public static void main(String[] args) {
        //创建对象
        Set<Integer> s = new HashSet<Integer>();

        //创建随机数对象
        Random r = new Random();

        while(s.size()<=10){
            //产生一个随机数添加到集合
            int number = r.nextInt(20)+1;

            s.add(number);
        }
        for(Integer i:s){
            System.out.println(i);
        }
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值