LinkedHashset的全面说明:
- LinkedHashSet是HashSet的子类
- LinkedHashSet底层是一个LinkedHashMap,底层维护了一个数组+双向链表
- LinkedHashSet根据元素的hashCode值来决定元素的存储位置,同时使用链表维护元素的次序,这使得元素看起来是以插入顺序保护的
- 不能有重复元素,效率没有haspmap高
说明:
- 在LinkedHashSet中维护了一个hash表和双向链表
- 每个节点都有before和after属性,这样形成双向链表
- 在添加一个元素时,先求hash值,再求索引值,确定该元素在table的位置,然后将添加的元素加入到双向链表(如果已经存在,不添加)
- 第一次添加时,直接将数组table扩容到16,存放的结点类型使LinkedHashmap$Entry
- 数组是HashMap$Node[]存放的元素/数据是LinkedHashMap$Entry类型
@后面是地址
Map接口和set的区别就是,set中的<k-v>中的v是PRESENT,是固定的默认的
Map中的v是自己输入的
Map接口实现类的特点:JDK8
- Map与Collection并列存在。用于保存具有映射关系的数据:key-value(双列元素)
- Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
- Map中的key不允许重复(和HashSet一样)
- Value可以重复,当有相同的key,就把newValue替换oldValue
- Map的key可以为null,value也可以为null,注意key为null,只能有一个,value为null可以有多个
- 一般来说String作为key
- Key和value之间是单向一对一的关系
- 一对k-v是放在一个Node中的,又因为Node实现了Entry接口,也可以说一对k-v就是一个Entry
解读源码:
- k-v最后是HashMap$Node node = newNode(hash,key,value,null)//底层是链表
- K-v为了方便程序员的遍历,还会创建EntrySet集合,该集合存放的元素的类型Entry,而一个Entry对象就有k,v transient Set<Map.Entry<K,V>>entrySet(本质上上是指向,其实EntrySet内部什么也没有,而是直接从table数组返回元素,建立EntrySet是为了方便遍历)
- entrySet中,定义的类型是Map.Entry,但是实际上存放的还是HashMap$Node
- 因为EntrySet内部实际不保存任何东西,而是通过迭代器返回他变了里面的节点
- 而table中的结点的类型Node又实现了Map.Entry接口,所以运行类型是Node,编译类型是Entry
为了能使用Map.Entry提供的重要方法K getKey() V getValue();
本质:为了方便管理Node,把它封装成了entry,,然后把所有entry的放到一个叫entrySet的集合里面去,entry里还写了很多方法利于遍历Node;
同理为了方便管理key,又有一个keySet:同理也有values
通过map.entryset可以返回map里的entryset
Map六大遍历方法:
第一组1.遍历方式增强for
2.就是迭代器
第二组把所有values取出
第三组:通过entryset来获取k-v
1.Map.Entry简介
Map是java中的接口,Map.Entry是Map的一个内部接口。
Map提供了一些常用方法,如keySet()、entrySet()等方法,keySet()方法返回值是Map中key值的集合;entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。
Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。
HashMap小结
- Map接口的常用实现类:HashMao Hasftable Properties
- HashMap是Map接口使用频率最高的实现类
- hashMap是以key-val对的方式来存储数据
- Key不能重复,但是值可以重复,允许使用null键和null值
- 添加相同的key,则会覆盖原来的key-val(等同于修改,key不会替换,val会)
- 与HashSet一样,不保证银环蛇的顺序,因为底层是以hash表(散列表)的方式来存储的
- HashMap没有实现同步,因此线程是不安全的
HashMap底层机制及源码剖析:
Jdk7底层是数组+链表 jdk8底层是数组+链表+红黑树(树的查询效率非常高,尤其是红黑树,这让我们在操作某一个结点的时候速度极快)
HashMap扩容机制上与HashSet完全一样
- HashMap底层维护了Node类型的数组table,默认是null
- 当创建对象时,将加载因子(loadfactor)初始化为0.75
- 当添加key-val时候,通过key获得在table的索引,然后根据索引判断索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的可以是否和准备加入的key相等,如果相等,则直接替换val;(之所以有这一步,是因为key相等,得到的索引一定一样,但是key不相等,也有概率索引一样);如股票不相等需要判断是树结构还是链表结构,做出相应处理,如果添加时发现容量不够,需要扩容。
- 第一次添加,则需要扩容table容量为16,临界值(threshold)为12(第13次put才会到)
- 以后再扩容,则需要扩容他变了容量为原来的2被
- 在java8中,如果一条链表个数到达8(第9次put才会扩容)并且table大小到达64就会树化成红黑树
Map接口实现类-Hashtable extends Dictionary
- 存放的元素是键值对:即K-V
- Hashtable的键和值都不能为null,否则会抛出NullPointerException
- Hashtable使用方法基本和HashMap一样
- Hash table是线程安全的,hashmap是线程不安全
Hashtable的底层:
- 底层有数组HashTable$Entry[] 初始化大小为11(整个table表里放的都是entry)
- Threshold 是 8 =11* 0.75,到了8[0-8]个(其实是第九次put时扩容的,因为比较的语句在count++前面)进行扩容,扩容是oldcapadacit×2+1
线程安全 效率 允许null键null值
HashMap 不安全 高 可以
Hashtable 安全 较低 不可以
Properties
- Properties类继承Hashtable类并实现了Map接口,也是使用一种键值对的形式来保存数据
- Properity还可以用于从xxx.properties文件中,加载数据到Properties类对象,并进行读取和修改
- Xxx.properities文件通常作为配置文件
- Properties键值不能为null;
- 如果有相同的key,那么值也会被替换
TreeSet:
- 当我们使用无参构造器,创建TreeSet时,默认是按首字母排序(默认key必须实现comparable接口的compareTo方法)
- 如果我希望按照字符串大小排序,可以使用TreeSet提供的一个构造器,可以传入一个比较器(匿名内部类),在里面指定排序规则
- 构造器会把传入的比较器对象,赋给了TreeSet底层的TreeMap的属性
- 根据string中compareTo返回的值构建平衡二叉树(红黑树:里面的fixafterInsertion是用来调整平衡的),输出用的中序遍历
- 重复的元素添加不进去,返回旧元素
TreeMap:
- 当我们使用无参构造器,创建TreeMap时,默认是按首字母排序(默认key必须实现compar接口的compareTo方法compareTo)
- 自定义comparator,逐步调式过程
这一步,构造器把咱们写的Comparator接口的匿名内部类(对象),传递给TreeMap的comparator
第一次进去树根为空,所以把put的key-value赋值给root根,第一次只有一个元素不进入比较器
遍历所有的key,给当前key找适当的位置挂进去,如果cmp=0(遍历过程中,发现准备添加的key和当前已有的key是相同的,key是加不进去的,但是旧的value替换成新的value)
第一次put,是自己和自己比
目的是检查key是否为null
Collections工具类
- Collections是一个操作Set、List和Map等集合的工具类
- Collection中提供一系列静态方法(不需要创建对象,非常方便)对集合元素进行排序、查询和修改等操作
- Copy(newlist oldlist)要求newlist》=oldlist