java中集合有List,Set,Map接口,List和Set都继承自Collection接口,而Map为独立接口
- List的具体实现类有ArrayList和LinkedList还有Vector
- Set下的具体实现类有HashSet和LinkedHashSet还有TreeSet
- Map下的具体实现类有HashTable和LinkedHashMap,还有HashMap和TreeMap
- Collection接口下还有个Queue接口,其具体实现类有PriorityQueue类
Collection和Map的区别:
- Collection是单列集合;Map是双列集合
- Collection中只有Set系列元素要求唯一;Map中键需要唯一,值可以重复
- Collection的数据结构是针对元素的;Map的数据结构是针对键的
泛型:类型的参数化
如果有泛型,不使用时,参数的类型会自动提升成Object类型,如果从集合中再取出来的话就需要向下强转,可能发生异常。不加泛型就不能在编译时限定向集合中添加元素的类型,导致后期的处理很麻烦
图解
LinkedList实现了Queue和List两种接口,如果在生成LinkedList时,方法参数是Queue,就完全只能访问Queue接口所定义的方法,而不能直接访问LinkedList中非Queue接口的方法。
SortedSet是个接口,里面的元素一定是有序的。
Collection接口
List(有序,可重复)
ArrayList
- 底层数据结构是数组,查询快,但增删慢
- 线程不安全,但效率高
Vector
底层数据结构是数组,查询快,增删慢
线程安全,效率低
LinkedList
底层数据结构是链表,查询慢,增删快
线程不安全但效率高
Set(无序,唯一)
HashSet
底层数据结构是哈希表(无序,唯一)
线程不安全,效率高,可以存储一个空元素
依赖重写hashCode()和equals()方法来保证元素唯一性
LinkedHashSet
底层数据结构是链表和哈希表
线程不安全,效率高
由链表保证元素有序,由哈希表保证元素唯一
TreeSet(当需要排序时才使用)
底层数据结构是红黑树,插入时自动排序,所以不允许空值
线程不安全,效率高
使用自然排序和比较器排序来保证元素排序
根据比较器的返回值是否为0来保证元素唯一性
List和Set的总结
- List和Set都是继承自Collection接口
- List特点:元素放入有顺序,并且可重复
Set特点:元素放入无顺序,并且不可重复,重复将会被覆盖 - List的位置可以由数组下标和for循环操作来对应获取
Set只能通过迭代器进行遍历取值,不能直接获取 - 对比
Set检索效率低,删除和插入效率高,并且不会引起位置改变
List检索效率高,删除和插入效率低,因为会发生位置改变,和数组很像但是可以动态增长长度。 - ArrayList与LinkedList的对比
- ArrayList的
优点:
实现了基于动态数组的数据结构,由于内存地址连续,当数据存储好时,查询操作效率会比较高
缺点:
因为地址连续,所以改变时要移动数据,导致插入和删除操作效率低 - LinkedList的
优点:
基于链表的数据结构,地址是任意的,所以在开辟内存空间的时候不需要等一个连续的地址,添加和删除的效率高。适用于要头尾操作或者插入指定位置的场景
缺点:
因为访问时要移动指针,所以查询性能低 - ArrayList和LinkedList的使用场景分析:当需要对数据进行多次访问时,用前者,当需要对数据进行多次增加删除修改时采用后者。
- ArrayList和Vector的对比
两者都是用数组实现
Vector是线程安全的,ArrayList是线程不安全的,效率上前者差后者很多。
两者都是采用线性连续空间存储元素,但是当空间不足时,增加的方式是不同的
Vector可以设置增长因子,但是ArrayList不可以 - 两者的使用场景分析
如果不考虑线程安全,一般用ArrayList效率比较高
如果集合中的元素的数据大于目前集合数组的长度时,在集合中使用数据量比较大的数据,用Vector由一定的优势 - TreeSet和HashSet的对比
TreeSet是红黑树实现的,数据是自动排好序的,不允许空值
HashSet是哈希表实现的,数据是无序的,只允许一个空值,两者都不能重复数据
HashSet要求放入的对象必须实现hashCode方法,放入的对象,是以hashcode码作为标识的,而具有相同内容的String对象,hashcode是一样的,所以放入的内容不能重复,但是同一个类的独享可以放入不同的实例 - 两者适用场景对比
HashSet是基于Hash算法实现的,其性能通常都由于TreeSet,为了快速查找,通常应该使用HashSet。当需要使用排序功能时,才用TreeSet
Map接口
TreeMap
有序,实现了SortedMap接口,是非线程安全的
基于红黑树对所有的key进行排序:自然排序和定制排序
TreeMap没有调优选项,因为该树一致处于平衡状态
TreeMap的key以TreeSet的形式存储,对key的要求与TreeSet对元素的要求基本一致
HashMap
父类是AbstractMap,基于数组和链表来实现
是无序的,非同步方法,允许多个空值和一个空key
线程不安全,执行效率高
HashTable
父类是Dictionary
是无序的,同步方法,不允许空值
线程安全,执行效率低
LinkedHashMap
使用双向链表来维护键值对的次序
迭代顺序与键值对的插入顺序保持一致
需要维护元素的插入顺序,所以性能低于HashMap
在访问元素的性能非常好,因为内部顺序是以链表实现的
面试题
- 性能分析:线程安全的有HashTable、ConcurrentHashMap、SynchronizedMap,性能最好的是ConcurrentHashMap
- HashMap的链表结构设计是用来解决什么问题的?
HashMap的链表结构设计是用来解决key的hash冲突问题的。 - 使用HashMap有什么性能问题吗?
使用HashMap要注意避免集合的扩容,它会很耗性能,根据元素的数量给它一个初始大小的值。 - HashMap的数据结构是怎样的?默认大小是多少?内部是怎么扩容的?
HashMap是数组和链表组成的,默认大小为16,当hashmap中的元素个数超过数组大小*loadFactor(默认值为0.75)时就会把数组的大小扩展为原来的两倍大小,然后重新计算每个元素在数组中的位置。 - HashMap怎么解决哈希冲突?
1.使用链地址法(散列表)来链接拥有相同hash值的数据
2.使用2次扰动函数(hash函数)来降低哈需冲突的概率,使得数据分布得更平均
3.引入红黑树进一步降低遍历的时间复杂度,使得遍历更快,快到O(logn)(JDK8才有) - 什么是哈希、哈希冲突?
hash,散列,就是把任意长度的输入通过散列算法,变换成固定长度的数据,这个值就是散列值(哈希值);一种将任意长度的信息压缩到某一长度的信息摘要的函数。
当两个不同的输入值,根据同一散列函数计算出相同的散列值的现象,就叫做哈希碰撞 - hashmap的主要参数都有哪些?
HashMap 的实例有两个参数影响其性能:初始容量 和加载因子。容量是哈希表中桶的数量,初始容量只是哈希表在创建时的容量。加载因子 是哈希表在其容量自动增加之前可以达到多满的一种尺度。