JAVA集合类

JAVA学习@集合类

集合类

第一次使用 CSDN进行总结,这篇文章用来记录总结学过的知识,如果有任何问题,欢迎指正。

1.集合(Collection)介绍

1.1为什么需要Collection

由来: 为了方便操作多个对象,将这多个对象存储起来,想要存储多个对象(变量)
常用的容器我们知道有:StringBuffered,数组(虽然有对象数组,但是数组的长度是不可变的!)
所以,Java就为我们提供了集合(Collection)

1.2 数组和集合的区别
(1)长度的区别
数组的长度固定,集合的长度可变
(2)元素的数据类型
数组可以存储基本数据类型,也可以存储引用类型
集合只能存储引用类型(你存储的是简单的int,它会自动装箱成Integer)

1.3 Collection体系结构

1.4 Collection基本功能

2.迭代器(Iterator)介绍

Collection的源码中继承了Iterable,有iterator()方法

Iterable是一个接口:只有三个方法:hasNext()、next()、remove()

ArrayList下有iterator实现的方法:它是在ArrayList以内部类的方式实现的!并且,从源码可知:Iterator实际上就是在遍历集合。

3.List集合

3.1 ArrayList、LinkedList、Vector的区别和实现原理。

ArrayList 和 Vector 基于数组实现的,LinkedList 基于双向循环链表实现的(含有头结点)。
ArrayList 和 Vector 只能按顺序存储元素(从下标为 0 的位置开始),删除元素的时候,需要移位并置空,默认初始容量都是 10。

3.2 线程安全性

ArrayList 和 LinkedList 是线程不安全的,如果在并发环境下使用它们, 可以用 Colletions 类的静态方法 synchronizedList() 对 ArrayList 和 LinkedList 进行调用即可。 Vector 是线程安全的,即它的大部分方法都包含有关键字 synchronized。Vector 的效率没有 ArrayList 和 LinkedList 高。

3.3 扩容机制

可变长度数组的原理:当元素个数超过数组的长度时,会产生一个新数组,将原数组 的数据复制到新数组,再将新的元素添加到新数组中。
从内部实现机制来讲,ArrayList 和 Vector 都是使用 Objec 数组形式来存储的。当你向这两种类型中增加元素的时候,若容量不够,需要进行扩容。ArrayList 扩容后的容量是之前的 1.5 倍,然后,把之前的数据拷贝到新建的数组。Vector 默认情况下扩容后的容量是之前的 2 倍
Vector 可以设置容量增量,而 ArrayList 不可以。 在 Vector 中有 capacityIncrement: 向量的大小大于其容量时, 容量自动增加的量。 如果在创建 Vector 时 , 指定了 capacityIncrement 的大小;则每次当 Vector 中动态数组容量需要增加时,如果容量的增量大于零,增加的大小都是 capacityIncrement。如果容量的增量小于等于零,则每次需要增大容量时,向量的容量将增大为之前的 2 倍。

3.4 增删查改的效率

ArrayList 和 Vector 中 ,从指定的位置(用 index)检索一个对象,或在集合的末尾插入、删除一个对象的时间是一样的,可表示为 O(1)。 但是,如果在集合的其他位置增加或 移除元素那么花费的时间是 O(n)。LinkedList 中,在插入、删除集合中任何位置的元素 所花费的时间都是一样的—O(1),但它在索引一个元素的时候比较慢 O(n)
     所以,如果只是查找特定位置的元素或只在集合的末端增加、移除元素,那么使用 Vector 或 ArrayList 都可以。如果是对其它指定位置的插入、删除操作,最好选择 LinkedList。

3.5 ArrayList源码解析

3.5.1 ArrayList体系结构

3.5.2 ArrayList的属性

ArrayList底层就是数组,ArrayList中有扩容这么一个概念,能够实现“动态”增长.

3.5.3 构造函数

3.5.4 Add(E e)方法

3.5.5 Add(int index, E element)方法

3.5.6 Get方法

3.5.7 Set方法

3.5.8 remove方法

ArrayList是基于动态数组实现的,在增删时候,需要数组的拷贝复制。

3.5 Vector源码解析

3.5.1 Vector的属性

3.5.2 构造函数

3.5.3 其他函数

Vector和ArrayList实现原理相同,不同在于加了锁

3.6 LinkedList源码解析

3.6.1 LinkedList的体系结构

3.6.2 LinkedList的属性

LinkedList实现了Deque接口,因此,我们可以操作LinkedList像操作队列和栈一样

3.6.2 构造函数

3.6.3 Add

add方法实际上就是往链表最后添加元素

public boolean add(E e) {
    linkLast(e);
    return true;
}

void linkLast(E e) {
    final Node<E> l = last;
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode;
    if (l == null)
        first = newNode;
    else
        l.next = newNode;
    size++;
    modCount++;
}

3.6.4 Remove方法

3.6.5 get方法(set方法类似)

public E get(int index) {
    checkElementIndex(index);
    return node(index).item;
}

4.Map集合

4.3.HashMap源码分析

4.3.1 HashMap体系结构

4.3.2 HashMap属性

4.3.3 HashMap的Entry

4.3.4 HashMap的构造函数

4.3.5 HashMap的Put函数

确定存储的位置:

在这里插入图片描述

4.3.6 HashMap的Get函数

4.3.6 HashMap的Remove函数

HashMap与Hashtable对比
从存储结构和实现来讲基本上都是相同的。它和HashMap的最大的不同是它是线程安全的,另外它不允许key和value为null。Hashtable是个过时的集合类,不建议在新代码中使用,不需要线程安全的场合可以用HashMap替换,需要线程安全的场合可以用ConcurrentHashMap替换

4.4 LindedHashMap集合

插入顺序和遍历顺序不同
最常用的将其放在链表的最后,不常用的放在链表的最前
因为它遍历的是LinkedHashMap内部维护的一个双向链表,而不是散列表
LinkedHashMap可以设置两种遍历顺序:
访问顺序(access-ordered)
插入顺序(insertion-ordered)
默认是插入顺序的

4.4.1 LindedHashMap体系结构

4.4.1 LindedHashMap的Entry重写

4.4.1 LindedHashMap的Get重写

4.5 TreeMap集合

4.5.1 TreeMap体系结构

4.5.2 TreeMap属性

4.5.3 TreeMap的Put方法

4.6 ConCurrentHashMap集合

4.6.1有了Hashtable为啥需要ConCurrentHashMap

Hashtable是在每个方法上都加上了Synchronized完成同步,效率低下。
ConcurrentHashMap通过在部分加锁和利用CAS算法来实现同步。
底层结构是散列表(数组+链表)+红黑树,这一点和HashMap是一样的。
Hashtable是将所有的方法进行同步,效率低下。而ConcurrentHashMap作为一个高并发的容器,它是通过部分锁定+CAS算法来进行实现线程安全的。CAS算法也可以认为是乐观锁的一种~
ConcurrentHashMap的key和Value都不能为null

5.Set集合

Set集合的就是Map 我们知道Map是一个映射,有key有value,既然HashSet底层用的是HashMap,那么value在哪里呢? value是一个Object,所有的value都是它

6.1.Collection 和 Collections 有什么区别?

Collection 是一个集合接口,它提供了对集合对象进行基本操作的通用接口方法,所有集合都是它的子类,比如 List、Set 等。
Collections 是一个包装类,包含了很多静态方法,不能被实例化,就像一个工具类,比如提供的排序方法: Collections. sort(list)。

6.2.HashMap 和 Hashtable 有什么区别?

存储:HashMap 运行 key 和 value 为 null,而 Hashtable 不允许。
线程安全:Hashtable 是线程安全的,而 HashMap 是非线程安全的。
推荐使用:在 Hashtable 的类注释可以看到,Hashtable 是保留类不建议使用,推荐在单线程环境下使用 HashMap 替代,如果需要多线程使用则用 ConcurrentHashMap 替代。

6.3.如何决定使用 HashMap 还是 TreeMap?

对于在 Map 中插入、删除、定位一个元素这类操作,HashMap 是最好的选择,因为相对而言 HashMap 的插入会更快,但如果你要对一个 key 集合进行有序的遍历,那 TreeMap 是更好的选择。

6.4 ArrayList 和 Vector 的区别是什么?

线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
性能:ArrayList 在性能方面要优于 Vector。
扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1 倍,而 ArrayList 只会增加 50%。

6.5. Array 和 ArrayList 有何区别?

Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。
Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。

6.6.说一下 HashMap 的实现原理?

HashMap 基于 Hash 算法实现的,我们通过 put(key,value)存储,get(key)来获取。当传入 key 时,HashMap 会根据 key. hashCode() 计算出 hash 值,根据 hash 值将 value 保存在 bucket 里。当计算出的 hash 值相同时,我们称之为 hash 冲突,HashMap 的做法是用链表和红黑树存储相同 hash 值的 value。当 hash 冲突的个数比较少时,使用链表否则使用红黑树。

6.7. 说一下 HashSet 的实现原理?

HashSet 是基于 HashMap 实现的,HashSet 底层使用 HashMap 来保存所有元素,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。

6.8 迭代器 Iterator 是什么?

Iterator 接口提供遍历任何 Collection 的接口。我们可以从一个 Collection 中使用迭代器方法来获取迭代器实例。迭代器取代了 Java 集合框架中的 Enumeration,迭代器允许调用者在迭代过程中移除元素。

6.9. Iterator 和 ListIterator 有什么区别?

Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
ListIterator 从 Iterator 接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置

6.10 怎么确保一个集合不能被修改?

可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。

6.11 Set里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()?

// 1. 如果key 相等
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
// 2. 修改对应的value
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}

添加元素的时候,如果key(也对应的Set集合的元素)相等,那么则修改value值。而在Set集合中,value值仅仅是一个Object对象罢了(该对象对Set本身而言是无用的)。

也就是说:Set集合如果添加的元素相同时,是根本没有插入的(仅修改了一个无用的value值)!从源码(HashMap)中也看出来,==和equals()方法都有使用!

6.12 Java中HashMap的key值要是为类对象则该类需要满足什么条件?

需要同时重写该类的hashCode()方法和它的equals()方法。

从源码可以得知,在插入元素的时候是先算出该对象的hashCode。如果hashcode相等话的。那么表明该对象是存储在同一个位置上的。
如果调用equals()方法,两个key相同,则替换元素
如果调用equals()方法,两个key不相同,则说明该hashCode仅仅是碰巧相同,此时是散列冲突,将新增的元素放在桶子上
一般来说,我们会认为:只要两个对象的成员变量的值是相等的,那么我们就认为这两个对象是相等的!因为,Object底层比较的是两个对象的地址,而对我们开发来说这样的意义并不大~这也就为什么我们要重写equals()方法

重写了equals()方法,就要重写hashCode()的方法。因为equals()认定了这两个对象相同,而同一个对象调用hashCode()方法时,是应该返回相同的值的!

6.13 与Java集合框架相关的有哪些最好的实践

1、根据需要确定集合的类型。如果是单列的集合,我们考虑用Collection下的子接口ArrayList和Set。如果是映射,我们就考虑使用Map~
2、确定完我们的集合类型,我们接下来确定使用该集合类型下的哪个子类~我认为可以简单分成几个步骤:

是否需要同步

去找线程安全的集合类使用
迭代时是否需要有序(插入顺序有序)

去找Linked双向列表结构的
是否需要排序(自然顺序或者手动排序)

去找Tree红黑树类型的(JDK1.8)
3、估算存放集合的数据量有多大,无论是List还是Map,它们实现动态增长,都是有性能消耗的。在初始集合的时候给出一个合理的容量会减少动态增长时的消耗~
4、使用泛型,避免在运行时出现ClassCastException
5、尽可能使用Collections工具类,或者获取只读、同步或空的集合,而非编写自己的实现。它将会提供代码重用性,它有着更好的稳定性和可维护性

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值