Set

继承自Collection的一个接口,特点是:无序,不可重复。注意啊!!只有Collection实现了迭代器!也就是说Map是没有实现迭代器的,需要keySet,values,entrySet这个几个方法

HashSet实现Set接口

SortedSet继承自Set接口,无序,不可重复,但是可以存进去的元素可以自动按照大小进行排序。TreeSet是他的一个实现类。

HashSet的底层是一个HashMap。为什么?因为HashMap中的key无序,不可重复,跟HashSet有一样的特性,一个没有value的HashMap不就是一个HashSet?

  1. public HashSet() {
  2. map = new HashMap<>();
  3. }

HashMap底层是一个哈希表

  1. transient Node<K,V>[] table;

哈希表是什么?是数组和单向链表的结合

哈希表的本质是一个数组,只不过这个数组中的每一个元素又是单向链表。类似于现实世界中的字典。

  1. static class Node<K,V> implements Map.Entry<K,V> {
  2. final int hash;
  3. final K key;
  4. V value;
  5. Node<K,V> next;
  6.  
  7. Node(int hash, K key, V value, Node<K,V> next) {
  8. this.hash = hash;
  9. this.key = key;
  10. this.value = value;
  11. this.next = next;
  12. }
  13.  
  14. ………
  15. ………
  16. }

代码中的hash是key通过hashCode()方法,再通过哈希算法得到的一个值。在单向链表中,每一个结点的哈希值是相同的。

所以哈希表的查找过程是:通过key来得到哈希值,得到值后定位单向链表,然后遍历该链表。哈希表的增删效率都是比较高的。

向哈希表添加元素:通过key得到一个哈希值,如何在这个表中不存在这个值,就直接添加元素。否则,继续调用equals(),如果返回false则添加该元素,否则不添加,因为返回true的话证明里面已经有这个元素了。

HashSet是HashMap的key部分。

HashSet和HashMap的初始化容量是16 ,默认加载因子是0.75。比方说:容量是100,那么在装了75个元素的时候开始扩容

注意:存储在HashSet和HashMap中key部分的元素,需要重写hashCode()和equals();

  1. public class HashSetTest {
  2.  
  3. public static void main(String[] args) {
  4. Set set = new HashSet();
  5. Employee e1 = new Employee("24" , "KOBE");
  6. Employee e2 = new Employee("21" , "TIM");
  7. Employee e3 = new Employee("21" , "KG");
  8. Employee e4 = new Employee("3" , "AI");
  9. Employee e5 = new Employee("3" , "DW");
  10. Employee e6 = new Employee("24" , "KOBE");
  11.  
  12. set.add(e1);
  13. set.add(e2);
  14. set.add(e3);
  15. set.add(e4);
  16. set.add(e5);
  17. System.out.println("set.size = " + set.size()); // set.size = 5
  18. }
  19.  
  20. }
  21. class Employee{
  22. String no;
  23. String name;
  24.  
  25. public Employee(String no , String name){
  26. this.no = no;
  27. this.name = name;
  28. }
  29.  
  30. @Override
  31. public int hashCode() {
  32. return no.hashCode(); //String已经重写了hashCode方法,直接用它的
  33. }
  34.  
  35. @Override
  36. public boolean equals(Object obj) {
  37. if (this == obj)
  38. return true;
  39. if (obj instanceof Employee){
  40. Employee e = (Employee)obj;
  41. if ( e.no.equals(this.no) && e.name.equals(this.name))
  42. return true;
  43. }
  44. return false;
  45. }
  46. }

SortedSet存储元素为什么可以自动排序?如何实现的?

  1. public class SortedSetTest {
  2.  
  3. public static void main(String[] args) {
  4. User u1 = new User("kobe");
  5. User u2 = new User("tim duncan");
  6. User u3 = new User("ray allen");
  7. User u4 = new User("melo");
  8.  
  9. SortedSet set = new TreeSet();
  10. set.add(u1);
  11. set.add(u2);
  12. set.add(u3);
  13. set.add(u4);
  14. }
  15.  
  16. }
  17.  
  18. class User{
  19. String name;
  20.  
  21. public User(String name){
  22. this.name = name;
  23. }
  24.  
  25. @Override
  26. public String toString() {
  27. return "[user name = " + name + "]";
  28. }
  29. }

上述代码运行时会报错:User cannot be cast to java.lang.Comparable

看下TreeSet的源码

  1. public TreeSet() {
  2. this(new TreeMap<E,Object>());
  3. }
  4.  
  5. public boolean add(E e) {
  6. return m.put(e, PRESENT)==null;
  7. }

发现底层是一个TreeMap。(其实跟HashSet类似,TreeSet也相当于TreeMap的key)

并且add()中是调用的TreeMap的put方法。这里再看下TreeMap的put方法源码。

  1. public V put(K key, V value) {
  2. ……
  3. ……
  4. else {
  5. if (key == null)
  6. throw new NullPointerException();
  7. @SuppressWarnings("unchecked")
  8. Comparable<? super K> k = (Comparable<? super K>) key; //强制转换成Compareble
  9. do {
  10. parent = t;
  11. cmp = k.compareTo(t.key); //转换完后调用compareTo方法
  12. if (cmp < 0) //小于0表示比根结点小,放左边
  13. t = t.left;
  14. else if (cmp > 0) //大于则放右边
  15. t = t.right;
  16. else
  17. return t.setValue(value);
  18. } while (t != null);
  19. }
  20. ……
  21. }

那么需要去实现这个Compareble接口,并重写compareTo方法。

  1. class User implements Comparable{
  2. String name;
  3. int age;
  4.  
  5. public User(String name , int age){
  6. this.name = name;
  7. this.age = age;
  8. }
  9.  
  10. @Override
  11. public String toString() {
  12. return "[user name = " + name + " , age = " + age + "]";
  13. }
  14.  
  15. @Override //该方法程序员负责实现,sun(或者说现在要叫oracle了 :) )提供的程序调用了该方法。
  16. public int compareTo(Object o) {
  17. //编写一个比较规则
  18.  
  19. //根据年龄排序
  20. int age1 = this.age;
  21. int age2 = ((User)o).age;
  22. return age1 - age2; //这个地方要注意只有在age的范围在一个足够小的时候才能这么干,如果age1是一个较大的整数,而age2是一个较小的负整数,age1-age2可能会溢出
  23. /*
  24. * [user name = melo , age = 2]
  25. [user name = kobe , age = 10]
  26. [user name = ray allen , age = 32]
  27. [user name = tim duncan , age = 200]
  28. */
  29. }
  30. }

那么也可以按照名字来排序,String本身实现了compareble接口,所以可以直接用。

  1. //根据名字来排序
  2. return name.compareTo(((User)o).name);
  3. /*
  4. * [user name = kobe , age = 10]
  5. [user name = melo , age = 2]
  6. [user name = ray allen , age = 32]
  7. [user name = tim duncan , age = 200]
  8. */

SortedSet实现排序还有一种方法,TreeSet中还有一个构造函数如下:

  1. public TreeSet(Comparator<? super E> comparator) {
  2. this(new TreeMap<>(comparator));
  3. }

通过传入Comparator的实现类的参数来进行比较。

TreeMap中的put方法源码一部分如下:

  1. Comparator<? super K> cpr = comparator;
  2. if (cpr != null) {
  3. do {
  4. parent = t;
  5. cmp = cpr.compare(key, t.key);
  6. if (cmp < 0)
  7. t = t.left;
  8. else if (cmp > 0)
  9. t = t.right;
  10. else
  11. return t.setValue(value);
  12. } while (t != null);
  13. }else{
  14. //这个else是之前说的第一种方法,可以看到java是优先使用Comparator这种方法的
  15.  
  16. }

那么就写一个Comparator的实现类,并删掉之前User实现的Compareble接口以及compareTo方法。如果不删的话,结果也是一样的,因为java优先使用这种方法排序。其实也是推荐这种方式的,因为这样User就是一个更加纯粹的User。这种方式也可以写成匿名内部类的方式,不过为了代码的复用,最好还是单独写出来。

  1. class UserComparator implements Comparator{
  2. @Override
  3. public int compare(Object o1, Object o2) {
  4. int age1 = ((User)o1).age;
  5. int age2 = ((User)o2).age;
  6.  
  7. return age1 - age2;
  8. }
  9. }

[user name = melo , age = 2]
[user name = kobe , age = 10]
[user name = ray allen , age = 32]
[user name = tim duncan , age = 200]

Set笔记的更多相关文章

  1. git-简单流程(学习笔记)

    这是阅读廖雪峰的官方网站的笔记,用于自己以后回看 1.进入项目文件夹 初始化一个Git仓库,使用git init命令. 添加文件到Git仓库,分两步: 第一步,使用命令git add <file ...

  2. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

  3. SQL Server技术内幕笔记合集

    SQL Server技术内幕笔记合集 发这一篇文章主要是方便大家找到我的笔记入口,方便大家o(∩_∩)o Microsoft SQL Server 6.5 技术内幕 笔记http://www.cnbl ...

  4. PHP-自定义模板-学习笔记

    1.  开始 这几天,看了李炎恢老师的<PHP第二季度视频>中的“章节7:创建TPL自定义模板”,做一个学习笔记,通过绘制架构图.UML类图和思维导图,来对加深理解. 2.  整体架构图 ...

  5. PHP-会员登录与注册例子解析-学习笔记

    1.开始 最近开始学习李炎恢老师的<PHP第二季度视频>中的“章节5:使用OOP注册会员”,做一个学习笔记,通过绘制基本页面流程和UML类图,来对加深理解. 2.基本页面流程 3.通过UM ...

  6. NET Core-学习笔记(三)

    这里将要和大家分享的是学习总结第三篇:首先感慨一下这周跟随netcore官网学习是遇到的一些问题: a.官网的英文版教程使用的部分nuget包和我当时安装的最新包版本不一致,所以没法按照教材上给出的列 ...

  7. springMVC学习笔记--知识点总结1

    以下是学习springmvc框架时的笔记整理: 结果跳转方式 1.设置ModelAndView,根据view的名称,和视图渲染器跳转到指定的页面. 比如jsp的视图渲染器是如下配置的: <!-- ...

  8. 读书笔记汇总 - SQL必知必会(第4版)

    本系列记录并分享学习SQL的过程,主要内容为SQL的基础概念及练习过程. 书目信息 中文名:<SQL必知必会(第4版)> 英文名:<Sams Teach Yourself SQL i ...

  9. 2014年暑假c#学习笔记目录

    2014年暑假c#学习笔记 一.C#编程基础 1. c#编程基础之枚举 2. c#编程基础之函数可变参数 3. c#编程基础之字符串基础 4. c#编程基础之字符串函数 5.c#编程基础之ref.ou ...

  10. JAVA GUI编程学习笔记目录

    2014年暑假JAVA GUI编程学习笔记目录 1.JAVA之GUI编程概述 2.JAVA之GUI编程布局 3.JAVA之GUI编程Frame窗口 4.JAVA之GUI编程事件监听机制 5.JAVA之 ...

随机推荐

  1. 单独谈谈 Android Cursor 的使用细节

    使用过 SQLite 数据库对 Cursor 应该不陌生,这里单独拿出来谈一下,加深对Android SQLite中使用 Cursor 的理解. 在你理解和使用 Android Cursor 的时候你 ...

  2. CentOS下Samba服务器的配置

    主要用途: 在两台计算机间共享文件.打印机 安装: yum install samba 启动服务: /etc/rc.d/init.d/smb start 添加用户  (必须是系统中真实存在的用户) s ...

  3. Hibernate 乐观锁(Optimistic Locking)

    1.hibernate基于数据版本(Version)记录机制实现.为数据增加一个版本标识,一般是通过为数据库表增加一个"version"字段来实现. 读取出数据时,将此版本号一同读 ...

  4. 为什么做Web开发要选择PHP

    大部分互联网公司做WEb开发都选择PHP,PHP的优势在哪?你应该知道的 以前偶尔被人问到,为什么你(和大部分互联网公司)做Web开发要选择PHP, PHP有什么好处.简单的回答便是“PHP简单,开发 ...

  5. 手机电话号码吉凶查询原理及ASP算法源码 转

    随着手机的快速普及,越来越多的人都在使用手机,而号码的挑选也是用户越来越关心的事情.虽然号码只是个代号而已,但几千年的传统积淀仍给号码赋予其各种含义,至于号码的吉凶也是见仁见智的一种个人喜好问题,或许 ...

  6. android脚步---APP引导页添加

    package com.leadcore.uudatoutie; import java.util.ArrayList; import com.leadcore.uudatoutie.R; impor ...

  7. 关于数据结构的10个面试题(c语言实现)

    关于数据结构的10个面试题(c语言实现) 2010-04-21 22:17 5702人阅读 评论(0) 收藏 举报 数据结构面试c语言bttree 1.         输入一个链表的头结点,从尾到头 ...

  8. Tomcat Neither the JAVA_HOME nor the JRE_HOME environment variable is defined

    一眼就能看出来是jdk的环境有问题,但是用了这么久的jdk一直都配置的好好的,怎么一到Tomcat上就这么矫情了. 最后查解决方案,原来是我的jdk从官网直接下载的,虽然我修改了java_home,但 ...

  9. 设计模式笔记之三:Android DataBinding库(MVVM设计模式)

    本博客转自郭霖公众号:http://mp.weixin.qq.com/s?__biz=MzA5MzI3NjE2MA==&mid=2650236908&idx=1&sn=9e53 ...

  10. A. Round House

    A. Round House time limit per test 1 second memory limit per test 256 megabytes input standard input ...