java 集合的原理_Java基础--集合实现原理

ArrayList特点(源码阅读):

A、总述:数据结构为线性表,用数组存储,可重复,有序,线程不安全。

查询修改快,删除,增加慢。

B、源码理解

数据结构是Object类型数组,默认容量(长度)是10,实现随机访问(访问速度快,按元素的添加顺序保存数据),删除和移动元素性能低,集合元素可重复,有序,线程不安全。

1、ArrayList() 创建一个初始长度是10的存放Objec类型数据的空列表。

2、add(E e) 把E元素追加到列表末尾。 ArrayList扩容的核心从ensureCapacityInternal,

①、使用无参构造方法,初始容量是0,首次添加元素是,默认容量是10,以后扩容按照当前容量的1.5倍扩容;

②、有参构造,参数为0和集合长度为0时,初始容量是0时,跟使用ArrayList() 创建方法作用一样,初始容量为0,一个一个添加时,添加1~4个元素扩容均为1,添加第5个及以后的元素,扩容是当前元素的1.5倍。

原因: 扩容后的容量 = (当前size++)  > (当前容量+当前容量 >> 1)  ?(当前size++)  :(当前容量+当前容量 >> 1).

具体算法是初始容量为0,添加一个元素扩容为1,再添加一个元素扩容为2,再添加一个元素扩容 为3,再添加一个元素扩容为4,再添加一个元素扩容为6。

3、get(int index)通过下标获取数组中的索引对应的元素。

4、size() 获取的是数组的长度, return size。

5、clear()方法 :将这个数组中的元素全部置为null。b.设置数组的长度size=0。

6、isEmpty()方法:判断size是否为0,如果为0则表示集合为空,否则就表示集合不为空。

C、APIs应用

C-1、遍历时删除元素方法:

一、正序删

正序删,如果只删除至多1个元素,那只需要在删除后使用break语句跳出循环即可,如果需要删除多个元素,若不注意控制当前列表的size和下一个元素的index,容易报java.lang.IndexOutOfBoundsException异常

public static void remove(List list, String target) {

for(int i = 0, length = list.size(); i < length; i++){

String item = list.get(i);

if(target.equals(item)){

list.remove(item);

length--;

i--;

}

}

}

二、倒序删

倒序删可以克服正序删需要额外管理列表size和下一个元素的index的问题,使用起来也很方便

public static void remove(List list, String target) {

for(int i = list.size() - 1; i >= 0; i--){

String item = list.get(i);

if(target.equals(item)){

list.remove(item);

}

}

}

三、迭代器remove()方法删除(推荐)

public static void remove(List list, String target) {

Iterator iter = list.iterator();

while (iter.hasNext()) {

String item = iter.next();

if (item.equals(target)) {

iter.remove();

}

}

}

四、CopyOnWriteArrayList线程安全删除

利用 CopyOnWrite容器。CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

public static List remove(ArrayList list, String target) {

CopyOnWriteArrayList cowList = new CopyOnWriteArrayList(list);

for (String item : cowList) {

if (item.equals(target)) {

cowList.remove(item);

}

}

return cowList;

}

注意:

使用CopyOnWriteArrayList的好处是我们不仅仅可以删除,也可以在遍历的得时候添加新元素。

以上方法并没有修改参数list,而是返回CopyOnWriteArrayList给调用者,也就是说CopyOnWriteArrayList并不修改构造它的List,而是自己内部维护着一个List,这一点要特别注意。

CopyOnWriteArrayList不是ArrayList的子类,但它实现了List接口。

五、增强for循环

增强for循环中删除元素后继续循环会报 java.util.ConcurrentModificationException 异常,因为元素在使用的时候发生了并发的修改,导致异常抛出,但是删除完毕马上使用break语句跳出循环,则不会触发报错,所以它适合删除至多1个元素。

public static void remove(List list, String target) {

for (String item : list) {

if (item.equals(target)) {

list.remove(item);

break;

}

}

}

六、stream API filter

Java8引入的stream API带来了新的比较简洁的删除List元素的方法filter,该方法不会改变原List对象,须返回新的对象,下面的例子演示了如何使用stream删除集合中的"*"元素。

List list = new ArrayList<>();

list.add("a");

list.add("b");

list.add("*");

list.add("c");

list.add("*");

List result = list

.stream()

.filter(item -> !"*".equals(item))

.collect(Collectors.toList());

C-2、遍历速度快慢:for循环

遍历方法:

ArrayList的遍历方式:

ArrayList支持3种遍历方式

(01) 第一种,通过迭代器遍历。即通过Iterator去遍历。

Integer value = null;

Iterator iter = list.iterator();

while (iter.hasNext()) {

value = (Integer)iter.next();

}

(02) 第二种,随机访问,通过索引值去遍历。

由于ArrayList实现了RandomAccess接口,它支持通过索引值去随机访问元素。

Integer value = null;

int size = list.size();

for (int i=0; i

value = (Integer)list.get(i);

}

(03) 第三种,for循环遍历。如下:

Integer value = null;

for (Integer integ:list) {

value = integ;

}

每日一题

使用cache命中率最高的算法是()

A、先进先出算法FIFO

B、随机算法RAND

C、先进后出算法FILO

D、替换最近最少使用的块算法LRU

********************************************************************************************************************************************************************************************************************************************************

A、总述:LinkedList数据结构是链表,双向链表。双向链表,那么它的顺序访问会非常高效,而随机访问效率比较低.

与ArrayList比较:当数据量很大或者操作很频繁的情况下,添加和删除元素时具有比ArrayList更好的性能。但在元素的查询和修改方面要弱于ArrayList。

LinkedList 是一个继承于AbstractSequentialList的双向链表。它也可以被当作堆栈、队列或双端队列进行操作。

LinkedList 实现 List 接口,能对它进行队列操作。

LinkedList 实现 Deque 接口,即能将LinkedList当作双端队列使用。

LinkedList 实现了Cloneable接口,即覆盖了函数clone(),能克隆。

LinkedList 实现java.io.Serializable接口,这意味着LinkedList支持序列化,能通过序列化去传输。

LinkedList 是非同步的。

B、源码理解

C、APIs应用

LinkedList遍历方式

LinkedList支持多种遍历方式。建议不要采用随机访问的方式去遍历LinkedList,而采用逐个遍历的方式。

(01) 第一种,通过迭代器遍历。即通过Iterator去遍历。

for(Iterator iter = list.iterator(); iter.hasNext();)

iter.next();

(02) 通过快速随机访问遍历LinkedList(不要用这种方式去遍历)

int size = list.size();

for (int i=0; i

list.get(i);

}

(03) 通过另外一种for循环来遍历LinkedList(可以用这种方式)

for (Integer integ:list)

;

(04) 通过pollFirst()来遍历LinkedList

while(list.pollFirst() != null)

;

(05) 通过pollLast()来遍历LinkedList

while(list.pollLast() != null)

;

(06) 通过removeFirst()来遍历LinkedList

try {

while(list.removeFirst() != null)

;

} catch (NoSuchElementException e) {

}

(07) 通过removeLast()来遍历LinkedList

try {

while(list.removeLast() != null)

;

} catch (NoSuchElementException e) {

}

由此可见,遍历LinkedList时,使用removeFist()或removeLast()效率最高。但用它们遍历时,会删除原始数据;若单纯只读取,而不删除,应该使用第3种遍历方式。

无论如何,千万不要通过随机访问去遍历LinkedList!

强烈建立不要用第二种方式去遍历LinkedList。

********************************************************************************************************************************************************************************************************************************************************

A、总述:

Vector 是矢量队列,它是JDK1.0版本添加的类。继承于AbstractList,实现了List, RandomAccess, Cloneable这些接口。

Vector 继承了AbstractList,实现了List;所以,它是一个队列,支持相关的添加、删除、修改、遍历等功能。

Vector 实现了RandmoAccess接口,即提供了随机访问功能。RandmoAccess是java中用来被List实现,为List提供快速访问功能的。在Vector中,我们即可以通过元素的序号快速获取元素对象;这就是快速随机访问。

Vector 实现了Cloneable接口,即实现clone()函数。它能被克隆。

和ArrayList不同,Vector中的操作是线程安全的。

B、源码理解

(01) Vector实际上是通过一个数组去保存数据的。当我们构造Vecotr时;若使用默认构造函数,则Vector的默认容量大小是10。

(02) 当Vector容量不足以容纳全部元素时,Vector的容量会增加。若容量增加系数 >0,则将容量的值增加“容量增加系数”;否则,将容量大小增加一倍。

(03) Vector的克隆函数,即是将全部元素克隆到一个数组中。

C、APIs应用

Vector支持4种遍历方式。建议使用下面的第二种去遍历Vector,因为效率问题。

(01) 第一种,通过迭代器遍历。即通过Iterator去遍历。

Integer value = null;

int size = vec.size();

for (int i=0; i

value = (Integer)vec.get(i);

}

(02) 第二种,随机访问,通过索引值去遍历。

由于Vector实现了RandomAccess接口,它支持通过索引值去随机访问元素。

Integer value = null;

int size = vec.size();

for (int i=0; i

value = (Integer)vec.get(i);

}

(03) 第三种,另一种for循环。如下:

Integer value = null;

for (Integer integ:vec) {

value = integ;

}

(04) 第四种,Enumeration遍历。如下:

Integer value = null;

Enumeration enu = vec.elements();

while (enu.hasMoreElements()) {

value = (Integer)enu.nextElement();

}

A、总述:

B、源码理解

C、APIs应用

*********************************************************************************************************************************************************************************************************

1数组和集合:

数组:存放同一种数据类型(基础数据类型或类),长度固定。通过下表访问。

集合:只能存储对象,类型可以不同;长度可变。

集合特点:

list有序,可重复,索引查询快,插入慢。

*********************************************************************************************************************************************************************************************************

基础面试题

1.介绍JAVA 中的Collection FrameWork(及如何写自己的数据结构)【基础】

答:Collection FrameWork 如下:

Collection:

├List

│├LinkedList

│├ArrayList

│└Vector

│ └Stack

└Set

Map

├Hashtable

├HashMap

└WeakHashMap

Collection 是最基本的集合接口,一个Collection 代表一组Object,即Collection 的元素(Elements); Map 提供key 到value 的映射。

2.List,Set,Map 是否继承自Collection 接口?【基础】

答:List,Set 是;Map 不是。

3.你所知道的集合类都有哪些?主要方法?【基础】

答:最常用的集合类是List 和Map。List 的具体实现包括ArrayList 和Vector,它们是可变大小的列表,比较适合构建、存储和操作任何类型对象的元素列表。List 适用于按数值索引访问元素的情形。Map 提供了一个更通用的元素存储方法。Map 集合类用于存储元素对(称作“键”和“值”),其中每个键映射到一个值。

4.说出ArrayList,Vector, LinkedList 的存储性能和特性?【基础】

答:ArrayList 和Vector 都是使用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,它们都允许直接按序号索引元素,但是插入元素要涉及数组元素移动等内存操作,所以索引数据快而插入数据慢,Vector 由于使用了synchronized 方法(线程安全),通常性能上较ArrayList 差,而LinkedList 使用双向链表实现存储,按序号索引数据需要进行前向或后向遍历,但是插入数据时只需要记录本项的前后项即可,所以插入速度较快。

5.Collection 和Collections 的区别?【基础】

答:Collection 是java.util 下的接口,它是各种集合的父接口,继承于它的接口主要有Set 和List;Collections 是个java.util 下的类,是针对集合的帮助类,提供一系列静态方法实现对各种集合的搜索、排序、线程安全化等操作。

6.HashMap 和Hashtable 的区别? 【基础】

答:二者都实现了Map 接口,是将惟一键映射到特定的值上;主要区别在于:

1)HashMap 没有排序,允许一个null 键和多个null 值,而Hashtable 不允许;

2)HashMap 把Hashtable 的contains 方法去掉了,改成containsvalue 和containsKey,因为contains 方法容易让人引起误解;

3)Hashtable 继承自Dictionary 类,HashMap 是Java1.2 引进的Map 接口的实现;

4)Hashtable 的方法是Synchronize 的,而HashMap 不是,在多个线程访问Hashtable 时,不需要自己为它的方法实现同步,而HashMap 就必须为之提供外同步。Hashtable 和HashMap 采用的hash/rehash 算法大致一样,所以性能不会有很大的差异。

7.Arraylist 与Vector 区别?【基础】

答:就ArrayList 与Vector 主要从二方面来说:

1)同步性:Vector 是线程安全的(同步),而ArrayList 是线程序不安全的;

2)数据增长:当需要增长时,Vector 默认增长一倍,而ArrayList 却是一半。

8.List、Map、Set 三个接口,存取元素时,各有什么特点?【基础】

答:List 以特定次序来持有元素,可有重复元素。Set 无法拥有重复元素,内部排序。Map 保存key-value 值,value 可多值。

9.Set 里的元素是不能重复的,那么用什么方法来区分重复与否呢? 是用==还是equals()? 它们有何区别? 【基础】

答:Set 里的元素是不能重复的,用equals ()方法来区分重复与否。覆盖equals()方法用来判断对象的内容是否相同,而”==”判断地址是否相等,用来决定引用值是否指向同一对象。

10.用程序给出随便大小的10 个数,序号为1-10,按从小到大顺序输出,并输出相应的序号。【基础】

public class RandomSort {public static void printRandomBySort() {Random random = new Random(); // 创建随机数生成器List list = new ArrayList();// 生成10 个随机数,并放在集合list 中for (int i = 0; i < 10; i++) {list.add(random.nextInt(1000));}Collections.sort(list); // 对集合中的元素进行排序Iterator it = list.iterator();int count = 0;while (it.hasNext()) { // 顺序输出排序后集合中的元素System.out.println(++count + ": " + it.next());

*********************************************************************************************************************************************************************************************************

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值