JavaSE精选-集合

简介: JavaSE精选-集合

集合

集合类的特点

a. 只能存储引用数据类型:因为泛型只能传入引用的数据类型

b. 可以自动地调整自己的大小

数组和集合类都是容器,它们有何不同?

a. 数组可以存储基本数据类型的数据,集合不可以。

b. 数组的长度是固定的,集合可以自动调整自己的大小。

c. 数组的效率高,相对来说集合效率比较低。

d. 数组没有API,集合有丰富的API。

集合类特点的回答顺序:

1, 是谁的子类, 描述了什么数据结构

2, 底层结构: 数组, 链表, 数组+链表, 数组(默认的初始容量, 扩容机制)

3, 有序, 重复, null 问题

4, 线程安全与否

Collection

特点

// 1, Collecion是Collection集合体系的顶级接口
// 2, Collection有些子实现有序, 有些子实现无序
// 3, Collection有些子实现允许存储重复元素, 有些子实现不允许存储重复元素
// 4, Collection有些子实现允许存储null, 有些子实现不允许存储null

API

boolean add(E e) 
          确保此 collection 包含指定的元素(可选操作)。 
 boolean addAll(Collection<? extends E> c) 
          将指定 collection 中的所有元素都添加到此 collection 中(可选操作)。 
 void clear() 
          移除此 collection 中的所有元素(可选操作)。 
 boolean contains(Object o) 
          如果此 collection 包含指定的元素,则返回 true。 
 boolean containsAll(Collection<?> c) 
          如果此 collection 包含指定 collection 中的所有元素,则返回 true。 
 boolean equals(Object o) 
          比较此 collection 与指定对象是否相等。 
 int hashCode() 
          返回此 collection 的哈希码值。 
 boolean isEmpty() 
          如果此 collection 不包含元素,则返回 true。 
 Iterator<E> iterator() 
          返回在此 collection 的元素上进行迭代的迭代器。 
 boolean remove(Object o) 
          从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。 
 boolean removeAll(Collection<?> c) 
          移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)。 
 boolean retainAll(Collection<?> c) 
          仅保留此 collection 中那些也包含在指定 collection 的元素(可选操作)。 
 int size() 
          返回此 collection 中的元素数。 
 Object[] toArray() 
          返回包含此 collection 中所有元素的数组。 
<T> T[]  toArray(T[] a) 
          返回包含此 collection 中所有元素的数组;返回数组的运行时类型与指定数组的运行时类型相同。
    
    
    
<T> T[]  toArray(T[] a) 
// 注意: toArray方法虽然是一个泛型方法, 可以接受一个泛型类型的数组, 但是并不意味着可以接受任何类型(因为在实际运行的时候如果这个给的数组存储不了会报错)    
// 如果给定的数组长度足够,  泛型的toArray方法, 参数和返回的数组是同一个数组
//  如果给定的数组长度不够, 返回的数组和参数数组没有关系, 是一个新数组, 参数数组仅仅起到类型推断的作用
// 如果我们给定的数组足够长, 并且collection中存储了n个元素, 那么数组中0-n-1位置存储collection的元素, 下标为n位置置位null,  之后位置不操作, 是数组原来存储的内容
boolean hasNext() 
          如果仍有元素可以迭代,则返回 true。 
 E next() 
          返回迭代的下一个元素。 
 void remove() 
          从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。 
    
在面试回答的时候,iterator一开始指向的是第一个元素的前一个位置,在调用next后指向的是第一个元素和第二个元素之间,这个时候输出的就是刚才跳过去的那个数。但实际的代码并不是这样实现的
// 注意1: remove方法
//       remove方法删除的是刚刚遍历过得元素, 注意是在源数据上删除
//       并且, remove不能在遍历之前进行, 也不能做连续的删除
//       这个删除操作更适用的场景是对某个元素遍历之后, 这个元素不符合预期我们才把他删除, 实际上对于iterator迭代来说, 重要是遍历而非删除
    
// 注意2: iterator遍历和操作数据, 操作的都是源数据, 并没有产生新的数据
    
// 注意3: 在iterator遍历的过程中, 为了保证在多线程的情况下, 数据在遍历的过程中遍历结果正确, 但是效率又足够高, 所以在iterator遍历的过程中增加了modCount(记录修改次数的同步机制), 由于设计的不够完美, 但是在单线程的情况下, 如果我们在遍历的过程中, 调用源集合的修改结构的方法修改了源集合类(modCount会变得不同步), 会导致并发修改异常产生.     
//一般用的是for each循环
//注意:for each循环默认调用的也是iterator,所以也会出现并发修改异常的情况
//数组也能使用for each循环,但默认调用的是fori循环

List

// 1, List是Collection的子接口
// 2, List所描述的数据结构是线性表
// 3, List有序
// 4, List允许存储重复元素
// 5, List允许存储null

API

ListIterator类型

boolean hasNext() : 判断后面是否还有元素可以遍历
 E next() : 向后遍历
 void remove() : 删除刚刚遍历过的元素
     
 boolean hasPrevious() : 判断前面是否还有元素可以遍历
 E previous() : 向前遍历
     
     
 int nextIndex() : 向后遍历的下标位置
 int previousIndex() : 向前遍历的下标位置
 void set(E e) : 修改刚刚遍历过的元素位置
 void add(E e) : 在当前遍历位置添加一个元素

subList: 是一个视图方法

注意: java中的集合类中有很多视图方法, 要注意视图返回的对象实际上并没有真正持有那个数据, 它持有的是一个标记和引用, 它通过这个标记和引用指向源数据

注意: 视图方法也伴随着并发修改异常, 原因和iterator迭代一样, 都是在已经开始了使用, 但是还未使用完成之前, 调用了源集合类的修改结构方法, 让源集合类发生了改变, 会导致迭代或者视图有问题(不再准确), 所以会抛出并发修改异常, 所以我们在使用iterator的时候和使用subList这种视图方法的时候, 不要在使用过程中调用了源集合类的修改结构方法.

ArrayList

ArrayList的特点
//ArrayList是List的一个子类,描述的是一个线性表
//ArrayList底层使用的是一个数组
//底层数组默认容量是10,扩容机制是1.5倍
//允许null,允许重复,有序,线程不安全

clone:返回的是一个浅表副本,复制该数组以及引用,但引用指向的内容还是一样的

Vector

特点
//Vector是List的一个自实现,1.0的时候出现的
//Vector底层使用的是一个数组
//数组默认容量是10,扩容机制:若存在一个增量,则扩容的是原容量+增量,默认是扩容2倍
//有序,允许重复,允许null,线程安全

Stack

//Stack是Vector的一个子类,底层基本上是复用Vector中的参数、结构、方法
//如果使用栈结构的时候最好使用Deque接口,而非stack,在使用多态的时候注意要根据实际的需求调用方法

LinkedList

特点
//LinkedList是List的一个子类,同时也是Deque的一个子实现
//LinkedList可以作为线性表、普通队列、双端队列、栈
//LinkedList底层使用的是一个双向链表
//LinkedList有序、允许重复、允许null、线程不安全
API
// LinkedList 的api的分类
//     1, 来自于Collection: 常见的,  添加和删除,
//     2, 来自于List:  根据下标的操作
//     3, 来自Queue:  队列方法, offer, poll, peek
//     4, 来自于Deque:  双端队列: offerFirst, offerLast, pollF...; addFirst, addLast..
//                      栈:  push, pop,

遵循要实现什么数据结构就使用什么方法的原则

Queue

Queue接口的特点

//Queue接口是Collection接口的一个子接口,描述的数据结构是队列
//Queue有序
//Queue允许重复
//Queue不允许null(LinkedList除外,因为他主要作为List的子类)
//不能存储null的原因:poll方法会返回一个null来表示没有数据可以出队列了,如果存储null有可能会产生歧义

Deque

//Deque的Queue的一个子接口,可以是普通队列、双端队列、栈
//Deque有序,不允许null(除了LinkedList),允许重复

ArrayDeque

//ArrayDeque是Deque的一个具体子实现
//ArrayDeque描述的数据结构是 普通队列、双端队列、栈
//ArrayDeque底层使用的是一个循环数组
//底层数组容量是16,扩容机制是原来的2倍
//允许重复,不允许null,有序,线程不安全
//如果指定一个容量,那么得到的最终结果是一个大于该值的最小的2的幂值

BlockingQueue

// 阻塞队列: 是一个容量优先的队列
//      当这个队列存储数据满的时候, 添加线程等待
//      当这个队列没有存储任何数据的时候, 删除线程等待
在使用按时等待的方法的时候注意,该方法并不会一直等待,如果有数据可以操作了会立即执行,如果超过等待的时间了会自动结束

Set

Set接口的特点

//Set接口是Collection接口的子类,描述的数据接口是集合
//所有子类都是不允许重复
//有些子类允许null,有些不允许null
//有些子类有序,有些无序

HashSet

//HashSet是Set接口的一个具体子类实现
//HashSet底层持有一个HashMap,存储都使用HashMap,并且作为一个key存在
//不允许重复,允许null,无序,线程不安全

LinkedHashSet

//HashSet的一个子类,底层持有LinkedHashMap
//存储到底层的LinkedHashMap中,并作为key存在
//有序(双向链表),不允许重复,允许null,线程不安全

TreeSet

//是Set的一个子类,底层是红黑树
//底层持有一个TreeMap,并且通过TreeMap存储Key值
//有序,不允许重复,不允许null
//存储的数据必须可以比较,自身实现了compare接口或者在构造方法中传入一个比较器

Map

Map是Map集合系列的顶级接口

Map中存储的是key-value数据,键值对:具有自我描述性

Map中所有的子类都不允许重复

Map中有些子类允许null,有些不允许null

Map中有些子类有序,有些无序

API

void clear() 
          从此映射中移除所有映射关系(可选操作)。 
 boolean containsKey(Object key) 
          如果此映射包含指定键的映射关系,则返回 true。 
 boolean containsValue(Object value) 
          如果此映射将一个或多个键映射到指定值,则返回 true。 
 Set<Map.Entry<K,V>> entrySet() 
          返回此映射中包含的映射关系的 Set 视图。 
 boolean equals(Object o) 
          比较指定的对象与此映射是否相等。 
 V get(Object key) 
          返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。 
 int hashCode() 
          返回此映射的哈希码值。 
 boolean isEmpty() 
          如果此映射未包含键-值映射关系,则返回 true。 
 Set<K> keySet() 
          返回此映射中包含的键的 Set 视图。 
 V put(K key, V value) 
          将指定的值与此映射中的指定键关联(可选操作)。 
 void putAll(Map<? extends K,? extends V> m) 
          从指定映射中将所有映射关系复制到此映射中(可选操作)。 
 V remove(Object key) 
          如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。 
 int size() 
          返回此映射中的键-值映射关系数。 
 Collection<V> values() 
          返回此映射中包含的值的 Collection 视图。 

HashMap

//HahshMap是Map的一个具体子实现。描述的数据结构是哈希表
//HashMap底层存储使用的是数组+链表+红黑树
//底层数组容量默认16,扩容机制是2倍,如果指定容量的话是得到一个大于等于该值的最小2的幂值
//不允许重复,有序,允许null,线程不安全
//加载因子默认0.75,实际能存储的阈值是数组长度*加载因子,注意这里存储指的是键值对数据的个数而非数组长度
//HashMap中链表的长度超过8到达9的时候有可能会转换为红黑树,如果数组长度小于64就会优先扩容,在扩容的过程中,原来下标为x位置的值得到的新下标有可能是x和x+原数组长度,就会减少链表的长度,可能就不会转换为红黑树
//在扩容和删除的过程中有可能会导致红黑树变为链表,在扩容的过程中可能会导致红黑树的拆分,当任意一个部分的节点数量小于6(提供一个缓冲的区间)就会转换为链表,同时如果根节点,根节点的左右节点,根节点的左节点的左节点中有一个为null,也会转变为链表
//hash值的计算:充分散列
//对于重复的定义:hash值相同,同时也要相equals或者==

LinkedHashMap

//LinkedHashMap是HashMap的一个子类,基本上复用了HashMap的底层结构
//额外维护了一个双向链表,用来记录元素的顺序
//有序,允许null,不允许重复,线程不安全

TreeMap

//TreeMap是Map的子类,底层的结构是红黑树
//有序,不允许null,不允许重复(大小一样),线程不安全
//存入TreeMap的必须自身实现compare接口或者在构造方法中传入一个比较器

Hashtable

与HashMap的区别:

Hashtable是1.0出现的,线程安全

底层存储使用的是数组+链表

不允许null

数组容量默认是11,扩容机制是2倍+1

目录
相关文章
|
4月前
|
存储 安全 Java
JavaSE—集合(零基础讲解完整版)
JavaSE—集合(零基础讲解完整版)
|
6月前
|
缓存 Java 编译器
JavaSE精选-栈和队列
JavaSE精选-栈和队列
30 1
|
6月前
|
Java
JavaSE精选-树
JavaSE精选-树
34 1
|
6月前
|
Java 编译器
JavaSE基础精选-1基础语法
JavaSE基础精选-1基础语法
35 0
|
6月前
|
存储 Java
JavaSE基础精选-IO流
JavaSE基础精选-IO流
43 0
|
6月前
|
Java API 调度
JavaSE基础精选-多线程
JavaSE基础精选-多线程
40 0
|
存储 Java 索引
【JavaSE】Java基础语法(二十八):HashSet集合
1. HashSet集合概述和特点 底层数据结构是哈希表 存取无序 不可以存储重复元素 没有索引,不能使用普通for循环遍历
|
算法 安全 Java
【JavaSE专栏47】Java常用类Collections解析,你了解JAVA集合类的通用用法吗?
【JavaSE专栏47】Java常用类Collections解析,你了解JAVA集合类的通用用法吗?
180 2
|
存储 Java 索引
【JavaSE专栏26】数组是什么?如何定义
【JavaSE专栏26】数组是什么?如何定义
|
存储 Java 容器
【JavaSE】Java基础语法(十二):ArrayList
集合和数组的区别 : 共同点:都是存储数据的容器 不同点:数组的容量是固定的,集合的容量是可变的