• Java Set集合(HashSet、TreeSet)


     什么是HashSet?操作过程是怎么样的?

      1、HashSet底层实际上是一个HashMap,HashMap底层采用了哈希表数据结构

      2、哈希表又叫做散列表,哈希表底层是一个数组,这个数组中每一个元素是一个单向链表,每个单向链表都有一个独一无二的hash值,代表数组的下标。在某个单向链表中的每一个节点上的hash值是相同的。hash值实际上是key调用hashCode方法,再通过"hash function"转换成的值

      3、如何向哈希表中添加元素?

        先调用被存储的key的hashCode方法,经过某个算法得出hash值,如果在这个哈希表中不存在这个hash值,则直接加入元素。如果该hash值已经存在,继续                调用Key之间的equals方法,如果equals方法返回false,则将该元素添加。如果equals方法返回true,则放弃添加该元素

        HashMap和HashSet初始化容量是16,默认加载因子是0.75

    HashSet的数据结构

      献上我看视频截的图

    代码举例

     1 public class Test{
     2     
     3     public static void main(String[] args) {
     4         
     5         Set set = new HashSet();
     6         
     7         Student stu1 = new Student("1", "JACK");
     8         Student stu2 = new Student("2", "TOM");
     9         Student stu3 = new Student("3", "JIM");
    10         
    11         set.add(stu1);
    12         set.add(stu2);
    13         set.add(stu3);
    14         
    15         System.out.println("size :" + set.size());
    16     }
    17     
    18
    19     
    20 }
    21 
    22 class Student{
    23     String no;
    24     String name;
    25     
    26     Student(String no, String name){
    27         this.no = no;
    28         this.name = name;
    29     }
    30 }

      这个的输出结果显而易见是3,因为我们添加了三个元素,但是如果改一下

    1 Student stu1 = new Student("1", "JACK");
    2 Student stu2 = new Student("1", "JACK");
    3 Student stu3 = new Student("3", "JIM");
    4 
    5 System.out.println(stu1.hashCode());
    6 System.out.println(stu2.hashCode());

      可以运行试一下,stu1和stu2的hashCode是不一样的,为什么呢?因为这两个对象是New出来的,引用地址不一样。我们不希望出现这样的情况,那就要重写hashCode和equals方法

     1 class Student{
     2     String no;
     3     String name;
     4     
     5     Student(String no, String name){
     6         this.no = no;
     7         this.name = name;
     8     }
     9     
    10     public boolean equals(Object o){
    11         if(this == o) return true;
    12         if(o instanceof Student){
    13             Student student = (Student) o;
    14             if(student.no.equals(this.no) && student.name.equals(this.name)) return true;
    15         }
    16         
    17         return false;
    18     }
    19     
    20     public int hashCode(){
    21         return no.hashCode();
    22     }
    23 }

      再次运行,插入两个数据一样的对象,就不会重复了

    TreeSet

      treeset实现了sortedset接口,有个很重要的特点是里面的元素都是有序的

     1 public class Test{
     2     
     3     public static void main(String[] args) {
     4         
     5         SortedSet set = new TreeSet();
     6         
     7         set.add(1);
     8         set.add(100);
     9         set.add(50);
    10         
    11         System.out.println(set);
    12     }
    13 
    14 }

      输出结果:[1, 50, 100]

      那如果我们自定义类可以进行比较吗?

     1 public class Test{
     2     
     3     public static void main(String[] args) {
     4         
     5         SortedSet set = new TreeSet();
     6         
     7         Student stu1 = new Student(22);
     8         Student stu2 = new Student(11);
     9         Student stu3 = new Student(100);
    10         
    11         set.add(stu1);
    12         set.add(stu2);
    13         set.add(stu3);
    14         
    15         System.out.println(set);
    16     }
    17 
    18 }
    19 
    20 class Student{
    21     int age;
    22     
    23     Student(int age){
    24         this.age = age;
    25     }
    26 }

      这样运行会出现一个问题,报ClassCastException,这就需要来看看源码了,底层到底是怎么实现的,为什么自定义类就先不行呢?

      这里可以看到,当我们在创建一个TreeSet的时候,实际上是new了一个TreeMap

      add的时候调用了TreeMap的put方法,来看看TreeMap中的put方法

       可以看到第三个红框那里,会对key进行一个强制类型转换,我们上面的代码肯定是就是在这里装换不成功,Comparable是什么?来看看API

      是一个接口,从翻译就可以看出,只要实现了这个接口,就是可以比较的,下面是实现了这个接口的类

      随便框了几个,上面就有Integer,这个类实现了comparable接口,因此第一个代码是正确的,现在我们是不是只要实现这个接口就好了呢!

     1 class Student implements Comparable{
     2     int age;
     3     
     4     Student(int age){
     5         this.age = age;
     6     }
     7 
     8     //重写接口中的方法
     9     //要重写比较规则
    10     @Override
    11     public int compareTo(Object o) {
    12         // TODO Auto-generated method stub
    13         int age1 = this.age;
    14         int age2 = ((Student)o).age;
    15         return age2 - age1;
    16     }
    17 }

      这样OK了,再来看看上面有红框的源码,cmp<0,cmp>0,left,right都是什么东西,二叉树!所以底层是通过二叉树来排序的

      如果是自定义类中的String呢,那就return String的compareTo方法就好了

  • 相关阅读:
    java开发异常类型汇总
    dm642在线写EPROM.txt
    [Codecademy] HTML&CSS 第一课:HTML Basic
    bram和dram差别
    Advanced Fruits HDU杭电1503【LCS的保存】
    add Admob with Cocos2d-x on iOS
    一种基于Qt的可伸缩的全异步C/S架构server实现(五) 单层无中心集群
    【SSH2框架(理论篇)】--SSH2 Vs 经典三层
    CSS BFC学习笔记
    【智能家居篇】wifi网络结构(上)
  • 原文地址:https://www.cnblogs.com/ccxka/p/9509984.html
Copyright © 2020-2023  润新知