集合真的太难了
在java中集合是一个庞大的框架体系,从jdk的层级结构来说,集合最顶层是一个叫做Iterable的接口。然后Iterable下面有个子接口叫做Collection,Collection下面又分为list、set、还有一个独立的键值对集合Map。首先我来阐述一下list集合把!list是一套有序、允许重复、可以存空值的集合。然后list下面又分为ArrayList、LinkedList、Vector。ArrayList的底层是一个Object数组,当我们实例化一个ArrayList的时候数组默认长度为0。当我们往里面追加第一个元素的时候,数组长度会变成10。如果ArrayList存储的元素达到一个临界点时会有一个自动扩容的机制,这个扩容的规律就是扩容到原数组的1.5倍。因此在实际的项目开发中为了避免频繁的扩容,我们在声明集合时,应该尽量确定它的初始大小。ArrayList底层扩容方式是调用arrayCopy方法将原有的数据复制到一个新的数组中再将原数组的指针引用指向新的数组。这样的话原数组就会被虚拟机标记为可被回收的垃圾等待被回收。ArrayList的特点是查询快,增删慢。是因为数组在内存中是一片连续的空间,根据下标查询不需要比较所以查询速度很快。而增删会带来元素的移动,所以影响效率。接下来是LinkedList,LinkedList的特点是查询慢,增删快。是因为LinkedList的底层是一个双向链表的结构。所谓的链表就是在每一个元素的前后都有一个引用节点。用来记住上一个元素和下一个元素的位置。在增删时只需要改变前后节点的引用,不需要移动其他元素的位置。所以增删速度很快,查询慢因为链表结构是没有下标的。也不是连续的空间需要一次次的遍历所有的元素。所以查询很慢。
然后是Vector,Vector底层其实就ArrayList,但是它是一个线程安全的集合。接下来介绍set集合,set是一套无序、不能重复、可以存空值的集合。set集合下面分为HashSet、LinkedHashSet、TreeSet、首先我来说一下HashSet,HashSet的底层就是HashMap,当HashSet添加元素时存到HashSet的值就是这个HashMap的Key,而这个HashMap的value就是一个Object。
HashSet是依靠hashcode和equals方法来区分重复值的。如果所存的值是一个基本数据类型的话,会自动装箱成一个包装类。基本数据类型的包装类都重写了这两个方法,可以直接去重。如果是自定义的类,必须要重写hashcode和equals方法才能保证储存在set集合的值不会重复。LinkedHashSet其实就是LinkedHashMap,它是一个哈希表+链表的结构,它的特点是有序,具有可预知的迭代顺序。 然后是TreeSet,TreeSet底层其实就是TreeMap,它可以进行元素排序的操作。如果是对基本数据类型进行操作,因为他们的包装类已经实现了Comparable接口所以可以直接排序。如果是自定义类要实现Comparable接口并重写compareTo。或者实现Comparator比较器并重写compare方法进行排序。在项目中我们要注意如果没有实现Comparable或者Comparator进行自定义类的排序会出现类无法转换的异常。最后是Map集合,Map是一套以键值对存储,key不能重复,但是valu可以重复的集合。Map集合下面分为HashMap,Hahstable,LinkedHashMap,TreeMap,ConcurrentHashMap。首先来说一下HashMap,HashMap采用Entry数组来存储key-value对,每一个键值对组成了一个Entry实体。底层是基于数组+链表+红黑树。
HashMap的主体是一个数组,默认长度是16,负载因子是0.75,阈值是12。当数组中的元素超过阈值会进行两倍扩容。HashMap中主要是通过key的hashCode来计算hash值的,如果存储的元素过多,有可能导致hashCode相同但是值不同,这就是hash冲突,链表就是为了解决hash冲突的,当链表的长度大于8并且数组长度大于64,会转化成红黑树进行更快的查询。然后是Hahstable,Hahstable是线程安全的,它的底层使用了synchronized关键字。但是它是一个全表锁的结构,多个线程竞争同一把锁,会造成效率低下。我们在项目中一般不会使用Hahstable,而会建议使用ConcurrentHashMap。因为ConcurrentHashMap使用分段锁的机制。每⼀把锁只锁容器其中⼀部分数据,多线程访问容器⾥不同数据段的数据,就不会存在锁竞争,能提高并发访问率。
接着说一下LinkedHashMap、LinkedHashMap底层是通过双链表的结构来维护节点的顺序的,是HashMap的子类并且是一个有序的集合。然后是TreeMap,TreeMap的底层是基于红黑树,红黑树结构天然支持排序,默认情况下通过Key值的自然顺序进行排序,或者使用Comparator接口进行排序。
在实际项目中,我们经常会对集合进行遍历,强烈建议使用迭代器,因为迭代器可以在遍历的同时进行业务逻辑操作。当我们想要对集合进行一系列的操作,比如我想查找一个元素是不是在这个集合当中,想求出这个集合的最大最小值,所以JDK为集合框架准备了一个非常强的一个类叫Collections,这个类中都是static的静态方法,可以帮我们解决这些问题。
for循环适合访问顺序结构,可以根据下标快速获取指定元素.而Iterator 适合访问链式结构,因为迭代器是通过next()和Pre()来定位的.可以访问没有顺序的集合.
我们在实际开发中,集合会遇到几个比较常见的异常,比如你在HashTable里存null,就报空指针,如果你强行在treeMap里存没有实现Comtarable的对象,就会报类无法转换的异常。
———————————睡觉睡觉 就好烦