JavaSE_集合

1.集合框架(继承关系)

1.1 Collection接口

  • Collection接口:下面有两大分支,List和Set。
  • List存储的数据,有顺序,允许重复;
  • Set存储的数据,没有顺序,不允许重复。

1.1.1 List接口


1.1.1.1实现类ArrayList集合类
  • 存储方式:
    1、底层数据结构基于"Object 数组"
    transient Object[ ] elementData;
  • 扩容机制:
    1、初始化长度为10;
    按照无参构造方法创建集合,底层数组默认长度为0,第一次添加元素时,默认增长至10。
    按照有参构造方法创建集合,底层数组按照指定长度创建。

    2、最大容量为:Integer.MAX_VALUE 或 Integer.MAX_VALUE - 8
    3、grow() 方法:按原有容量的1.5倍进行扩容
  • 应用特点:
    1、实现RandomAccess接口:支持高效的随机元素访问(可以使用下标高速访问)
    2、插入删除元素效率低
    3、线程不安全
    4、性能高

1.1.1.2实现类Vector集合类
  • 存储方式:
    1、底层数据结构基于"Object 数组"
    protected Object[] elementData;
  • 扩容机制:
    1、初始化长度为10
    2、最大容量为:Integer.MAX_VALUE 或 Integer.MAX_VALUE - 8
    3、grow() 方法:按原有容量的2倍进行扩容
  • 应用特点:
    1、实现RandomAccess接口:支持高效的随机元素访问
    2、插入删除元素效率低
    3、方法中使用synchronized,保证线程安全
    4、性能差

1.1.1.3实现类LinkedList集合类
  • 存储方式:
    1、底层数据结构基于"双向链表"
    JDK1.6之前为循环链表
    JDK1.7取消了循环
  • 扩容机制:
    双向链表,没有初始化大小,也没有扩容的机制,就是一直在前面或者后面新增就好
  • 应用特点:
    1、不支持高效的随机元素访问(未实现RandomAccess接口)
    2、插入元素效率高
    3、线程不安全

1.1.2 Set接口


1.1.2.1 HashSet集合类
  • 存储方式:底层数据结构基于"HashMap"
    private transient HashMap<E,Object> map;
  • 应用特点:
    1、线程不安全。
    2、存取速度快。

1.1.2.2 LinkedHashSet集合类
  • 存储方式:底层数据结构基于“LinkedHashMap"
    super(16, .75f, true);
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
  • 应用特点:
    1、线程不安全。
    2、存取速度快。
    3、链表维持存入顺序。

1.1.2.3 SortedSet接口——>TreeSet集合类
  • 存储方式:底层数据结构基于"TreeMap"
    public TreeSet() {
    this(new TreeMap<E,Object>());
    }
  • 应用特点:
    1、线程不安全。
    2、存取速度快。
    3、自动排序。(必须实现Comparable接口)

1.1.3 其他常用接口与类(Queue接口和Stack类)


1.1.3.1 Queue接口
  • 存储方式:Queue接口直接实现Collection接口
  • 应用特点:
    1、维护了一个普通队列
    2、只许从一端进,另一端出。
1.1.3.2 Deque接口
  • 存储方式:Deque接口实现Queue接口
  • 应用特点:
    1、维护了一个双端队列
    2、允许执行两端进或者两端出操作。

Queue接口(队列)的子类为Deque接口(双端队列)LinkedList既实现了List接口又实现了Deque接口所以它既可以当做链表的实现类又可以当做队列的实现类。


1.1.3.3 Stack类
  • 存储方式:Stack类继承Vector类;
  • 应用特点:
    1、维护了一个栈
    2、只允许从一个端口进栈和出栈。

因为Stack类实现了Vector类所以它的存储方式,扩容机制,应用特点和Vector一致。


1.2 Map接口

  • KV(key - value)键值对集合

1.2.1 HashMap类

  • 存储方式:
    1、基于哈希表(Hash Table)设计:
    JDK1.7 : 底层数据结构基于“数组”+“链表”
    JDK1.8 : 底层数据结构基于“数组”+“链表”+“红黑树”(当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间)

    2、transient Node<K,V>[ ] table;
  • 扩容机制:
    1、初始容量为16
    2、加载因子为0.75:当 元素个数 超过 容量长度的0.75倍 时,进行扩容
    3、按原有容量的2倍进行扩容
  • 应用特点:
    1、线程不安全
    2、性能高
    3、允许Null key和Null value,Null Key只允许有1个,Null value 可以有多个

1.2.2 LinkedHashMap类

  • 存储方式:
    1、继承自HashMap,链表采用“双向链表”
    2、 Entry<K,V> before, after;
  • 应用特点:
    1、线程不安全
    2、有序

1.2.3 SortedMap接口——>TreeMap类

  • 存储方式:
    1、底层数据结构基于“红黑树”
    2、private transient Entry<K,V> root;
  • 应用特点:
    1、线程不安全
    2、自动排序(必须实现Comparable接口)

1.2.4 Hashtable类

  • 存储方式:底层数据结构基于“数组”+“链表”
  • 扩容机制:
    1、默认为11
    2、每次扩容后,容量变为原来的2n+1
  • 应用特点:
    1、线程安全
    2、性能差
    3、不允许有Null value,会导致NullPointerException

2.集合应用(具体应用)


2.1 Collections集合算法类

1、void sort(List)
对List容器内的元素排序,排序规则是按照升序进行排序
2、void shuffle(List)
对List容器内的元素进行随机排列。
3、void reverse(List)
对List容器内的元素进行逆序排列。
4、void fill(List,Object)
用一个特定的对象重写整个List容器
5、int binarySearch(List,Object)
对于顺序的List容器,采用折半查找的方法查找特定对象。
6、boolean addAll(collection con,E e…)
将一组值添加到集合
7、boolean disjoint(Collection con1,Collection con2);
比较两个集合中是否存在相同元素。存在返回false,不存在返回true。
8、int indexOfSubList(List list1,List list2);
在list1集合中查找list2的位置。
9、List nCopies(int num,Collection con);
对con集合进行num倍的复制返回为嵌套集合。
10、boolean replaceAll(List list ,E old,E new);
将list集合中old值全部替换为new
11、void rotate(List list int num);
当num大于0则将list后面的num尾提前,如果num小于0则将list前面num绝对值位放到最后。(旋转集合、)
12、List emptyList();
产生一个List类型的空集合。
13、Set emptySet();
产生一个Set类型的空集合。
14、Map emptyMap();
产生一个Map类型的空集合。
15、List synchronizedList(List list);
将list集合改造为线程安全的synchronized集合。
16、Set synchronizedSet(Set set);
将set集合改造为线程安全的synchronized集合。
17、Map synchronizedMap(Map map);
将map集合改造为线程安全的synchronized集合。
18、List unmodifiableList(List list);
产生一个不允许修改的List集合。
19、Set unmodifiableSet(Set set);
产生一个不允许修改的Set集合。
20、Map unmodifiableMap(Map map);
产生一个不允许修改的Map集合。


2.2 Collection接口

1、void add(E e);
添加元素。
2、void clear();
暴力清除集合中所有的元素。
3、boolean contains(Object obj);
判断集合是否包含某个元素
4、boolean isEmpty(),
判断集合是否为空;如果此集合不包含元素,则返回true。
5、Iterator iterator();
生成迭代器。
6、int size();
返回集合中的元素个数。
7、Object[] toArray();
使集合转化为数组


2.3 List接口新增方法

1、void add(int index,E element);
添加功能 :在指定位置添加元素。
2、E get(int index);
获取功能:获取指定位置的元素。
3、ListIterator listlterator();
List:特有的迭代器。该迭代器继承了Iterator迭代器,所以,就可以直接使用hasNext()和next()方法。
4、E remove(int index);
删除功能:根据索引删除元素,返回被删除的元素。
5、E set(int index,E element);
替换功能:根据索引替换元素,返回被替换的元素。
6、int indexOf(Object);
查找当前集合中是否存在指定元素。找到返回下标没找到返回-1
7、int lastIndexOf(Object);
查找当前集合最后一次出现元素的位置。
9、List subList(int begin, int end);
从begin开始到end截取集合


2.4 ArrayList独有方法

void trimToSize()
将集合的实际长度缩小为size长度,实际上就是把ArrayList后面没有存数据的部分删除减少空间的使用


2.5 Vector独有方法

1、void addElement(E e)
添加元素等同于add()方法
2、E elementAt(int index)
根据下标返回元素等同于get()方法
3、void setElementAt(E e,int index);
根据下标修改元素等同于set()方法
4、int capacity();
返回集合的容量,Vector和ArraysList区别之一,由于Vector线程安全所以可以返回集合容量。


2.6 Iterator(迭代器类)

1、boolean hasNext();
判断是否存在元素
2、E next();
获取到该元素。


2.7 TreeSet 独有方法

1、E lower(E e);
返回小于指定元素的第一个元素
2、E floor(E e);
返回小于等于指定元素的第一个元素
3、E higher(E e);
返回大于指定元素的第一个元素
4、E ceiling(E e);
返回大于等于指定元素的第一个元素
5、E first();
获取集合中的第一个元素
6、E last();
获取集合中最后一个元素
7、E pollFirst();
弹出集合中第一个元素
8、E pollLast();
弹出集合中最后一个元素


2.8 Map接口主要方法

1、int size();
获取map集合的大小。
2、Collection values();
获取map集合类所有的值(Value)
3、Set keySet();
获取map集合所有的键(key)
4、E get(E key);
通过键(key)的名字获取值(value)
5、E remaove(E key)
通过key移出与key相对应的value
6、boolean remave(E key,E value)
移除key以及key对应的value值
7、void put(E key,E value)
添加元素。
8、void clear();
暴力清除集合中所有的元素。
9、boolean containsKey(E key);
检查当前集合中是否包含指定元素key
10、boolean containsValue(E value);
检查当前集合中是否包含指定元素value
11、boolean isEmpty();
判断当前集合是否为空。
12、V getOrDefault(E key,默认值);
如果该集合中存在key则返回对应的value,如果不存在key则返回默认值。
13、V putIfAbsent(E key, E value);
如果该集合中存在key不进行操作,如果不存在key则添加key和相应的value。该方法和put方法之间的区别:如果使用put()方法当集合中存在相应的key则新的value会覆盖旧的,这个方法,如果存在相应的key新的value不会覆盖旧的value
14、V replace(E key,E newvalue);
按照key,将key所对应的value替换成newvalue。
15、boolean replace(E key,E oldvalue,E newvalue);
按照key和oldvalue,如果与当前集合内的KV,键值对一致则用newvalue替换,否则不替换。
16、void putAll(Map map);
把一个map集合添加到另一个map集合中。


2.9 TreeMap独有方法:

1、E lowerKey(E key);
找到小于指定key的一个key,找到返回key找不到返回null
2、Entry lowerEntry(E key);
找到小于指定key的Entry键值对(KV)
3、E higherKey(E key);
找到大于指定key的一个key,找到返回key找不到返回null
4、Entry higherEntry(E key);
找到大于指定key的Entry键值对(KV)
5、E floorKey(E key);
找到小于等于指定key的一个key,找到返回key找不到返回null
6、Entry floorEntry(E key);
找到小于等于指定key的Entry键值对(KV)
7、E ceilingKey(E key);
找到大于等于指定key的一个key,找到返回key找不到返回null
8、Entry ceilingEntry(E key);
找到大于等于指定key的Entry键值对(KV)
9、E firstKey();
获取Map集合中的第一个key。
10、Entry firstEntry();
获取Map集合中的第一个键值对(KV)。
11、E lastKey();
获取Map集合中最后一个key。
12、Enter lastEnter();
获取Map集合中最后一个键值对(KV)。
13、Enter pollFirstEnter();
弹出第一个元素。
14、Enter pollLastEnter();
弹出最后一个元素。
15、Map headMap(E key ,boolean bool);
按照指定的key,从map集合的头部键值对开始截取,截取至指定key之前默认不包含指定键值对,可以通过第二个boolean型参数来决定是否包含指定KV键值对。
16、Map tailMap(E key,boolean bool);
按照指定的key,从map集合的尾部键值对开始截取,截取至指定key之前默认不包含指定键值对,可以通过第二个boolean型参数来决定是否包含指定KV键值对。
17、Map subMap(E beginkey,boolean是否包含开始的KV,E endkey,boolean 是否包含结束的KV);
按照开始beginkey进行截取,截取至结束的endKey。


2.10 Entry(map集合封装一个KV键值对)

1、K getKey();
获取key
2、V getValue();
获取Value


2.11 Stack(栈)

1、E pop();
弹出栈顶元素。
2、E Push(E e);
从栈顶压入元素。
3、E peek();
查看栈顶元素。
4、int search(E e)
查找元素的位置。


2.12 Queue(队列)

1、E poll()
弹出队首元素。
2、E offer(E)
添加元素。
3、E peek()
查看队首元素。


2.13 Deque(双端队列)

1、E offerFirst(E e);
在双端队列前端添加一个元素
2、E offerLast(E e);
在双端队列后端添加一个元素
3、E pollFirst();
移出并返回双端队列头部的元素
4、E pollLast();
移出并并返回双端队列尾部的元素
5、E peekFirst();
返回队列头部的元素
6、E peekLast();
返回队列尾部的元素
7、void addFirst(E e);
添加至头部
8、void addLast(E e);
添加至尾部
9、E removeFirst();
删除头部元素
10、E removeLast();
删除尾部元素
11、boolean removeFirstOccurrence(E e)
删除集合中第一个找到的指定元素
12、boolean removeLastOccurrence(E e)
删除集合中最后一个找到的指定元素
13、E getFirst();
获取头部元素
14、E getLast();
获取尾部元素


3.集合常见面试题


  • Arraylist 与 LinkedList 区别?
    1、是否保证线程安全。
    ArrayList和LinkedList都是不同步的,也就是不保证线程安全。
    2、底层数据结构。
    ArrayList底层使用的是Object数组;
    LinkedList底层使用的是双向链表数据结构;
    JDK1.6之前为循环链表,
    JDK1.7取消了循环
    注意双向链表和双向循环链表的区别。
    3、插入和删除是否受元素位置的影响。
    1、ArrayList采用数组存储,所以插入和删除元素的时间复杂度受元素位置的影响。
    如果执行add(E e)方法的时候,ArrayList默认将指定元素追加到此列表的末尾,这种情况时间复杂度为O(1)。
    如果执行add(int index,E e)方法的时候,在指定位置 index位置插入和删除e元素,这种情况时间复杂度为O(n-index)。因为进行该操作需要大量移动数组内元素。
    2、LinkedList采用链表存储,所以对于add(E e )方法的插入,删除元素时间复杂度不受元素位置的影响。
    如果执行add(E e)方法的时候,时间复杂度不受位置的影响,近似O(1)。
    如果执行add(int index,E e)方法的时候,在指定位置index位置插入和删除元素,时间复杂度为O(n);因为需要先移动到指定位置再插入。
    4、是否支持快速随机访问。
    1、ArrayList支持快速随机访问。
    2、LinkedList不支持快速随机访问。
    快速随机访问就是通过元素的序号快速获取元素对象(对应于get(int index)方法)。
    5、内存空间占用。
    1、ArrayList的空间浪费主要体现在list列表的结尾会预留一定的容量空间。
    2、LinkedList的空间花费则体现在它的每一个元素都需要消耗比ArrayList更多的空间(因为要存放直接后继和直接前驱以及数据)。

  • ArrayList 与 Vector 区别呢?
    1、Vector类的所有方法都是同步的。可以由两个线程安全地访问一个Vector对象,但是一个线程访问Vector的话代码要在同步操作上消耗大量的时间。
    2、ArrayList不是同步的,所以在不需要保证线程安全时建议使用ArrayList。

  • ArrayList 的扩容机制?
    创建ArrayList时,实际上初始化赋值的是一个空数组,长度为0.
    执行Add操作向数组中添加第一个元素时,数组扩为10;
    int newCapacity = oldCapacity+(oldCapacity>>1)
    可知:ArrayList每次扩容后容量都会变为原来的1.5倍。

  • HashMap如何检查重复?
    java中的HashMap使用hashCode和equals方法来确定键 - 值对的索引。这些方法也可用于当我们请求一个特定键的值。如果这些方法都不能正确执行,两个不同的密钥,可能会产生相同的散列值,因此,可以考虑这两个集合相等。此外,这些方法也被用来检测是否有重复。因此,这两种方法的执行对于HashMap中的精确性和正确性是至关重要的。

  • HashMap如何工作的?
    java中的HashMap中存储键 - 值对。HashMap中需要一个散列函数,并使用hashCode和equals方法中,为了把元素放入集合中或获取出来,当调用put方法,HashMap计算键的哈希值,并对集合内的数值比较。如果该键存在,更新为新值。HashMap一些重要特点是它的容量,其负载系数和阈值调整大小。

  • HashMap 和 Hashtable 的区别?
    1、线程是否安全:
    HashMap是非线程安全的,
    Hashtable是线程安全的;Hashtable内部的方法基本都经过synchronize修饰。
    如果你非要保证线程安全那就使用ConcurrentHashMap吧!)
    2、效率:
    HashMap效率高
    Hashtable效率低
    Hashtable基本被淘汰不要在代码中使用。
    3、对Null key 和Null value的支持
    HashMap中,null可以作为键,这样的键只有一个,可以有一个或者多个键对应的值为null。
    Hashtable中put进的键值只要有一个为null,直接抛出NullPointerException。
    4、初始容量大小和每次扩充容量大小的不同:
    (1)创建时如果不指定容量初始值。
    Hashtable默认的初始大小为11,之后每次扩容,容量变为原来的2n+1
    HashMap默认初始化大小为16.之后每次扩容,容量变为原来的2倍。
    (2)创建时如果给定了容量初始值。
    Hashtable会直接使用你给定的大小,
    HashMap会将其扩充为2的幂次方大小
    HashMap中的tableSizeFor()方法保证
    也就是说使用HashMap总是使用2的幂作为哈希表的大小。
    5、底层数据结构。
    JDK1.8以后的HashMap在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。
    Hashtable没有这样的机制。
  • RandomAccess接口
    1、RandomAccess是什么?
    源码:public interface RandomAccess{ };
    查看源码我们发现实际上RandomAccess接口中什么都没有定义。所以在我看来RandomAccess接口不过是一个标示罢了。标示什么?
    标示实现这个接口的类具有随机访问功能。
    2、在binarySearch()方法中,它要判断传入的list是否RandomAccess的实例。
    如果是调用indexedBinarySearch()(下标快速搜索)
    如果不是调用iteratorBinarySeach()(迭代器搜索)
    3、ArrayList实现了RandomAccess接口,而LinkedList没有实现。为什么?
    我觉得还是和底层数据结构有关!
    ArrayList底层是数组,而LinkedList底层是链表。
    数组天然支持随机访问,时间复杂度为O(1),所以称为快速随机访问。
    链表需要遍历到特定位置才能访问特定位置的元素,时间复杂度为O(n),所以不支持快速随机访问。
    ArrayList实现了RandomAccess接口,就表明了他具有快速随机访问功能。
    RandomAccess只是标识,并不是说ArrayList实现RandomAcc接口才具有快速随机访问的功能。
    4、总结一下List的遍历方式选择:
    实现了RandomAccess接口的List,优先选择普通for循环,其次foreach,
    未实现RandomAccess接口的List,优先选择iterator遍历(foreach遍历底层也是通过iterator实现的),大Size的数据,千万不要使用普通for循环。

  • 集合框架底层数据结构总结:
    一、Collection
    (1)List
    1.ArrayList——Object数组
    2.Vector——Object数组
    3、LinkedList——双向链表(JDK1.6之前为循环链表,JDK1.7取消了循环)。
    (2)Set
    1.HashSet(无序,唯一)
    基于HashMap实现的,底层采用HashMap来保存元素。
    2.LinkedHashSet
    LinkedHashSet继承于HashSet,并且其内部是通过LinkedHashMap来实现的。有点类似于我们之前说的LinkedHashMap其内部是基于HashMap实现一样,不过还是有一点点区别的。
    3.TreeSet(有序,唯一)
    红黑树(自平衡的排序二叉树)
    二、Map
    (1)HashMap
    JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决哈希冲突)。JDK1.8以后再解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间。
    (2)LinkedHashMap
    LinkedHashMap继承自HashMap,所以它的底层依然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
    (3)Hashtable
    数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的。
    (4)TreeMap
    红黑树(自平衡的排序二叉树)

未完待续。。。。。。。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值