Java-集合框架-学习总结

Java 集合框架

集合框架被设计成要满足以下几个目标。

该框架必须是高性能的。基本集合(动态数组,链表,树,哈希表)的实现也必须是高效的。

该框架允许不同类型的集合,以类似的方式工作,具有高度的互操作性。

对一个集合的扩展和适应必须是简单的
在这里插入图片描述

集合框架主要有两种类型的容器,一是集合(collection),存储一个元素集合,另外一个是图(map),存储键/值对映射。
Collection 接口有三种子类,List, Set, Queue,在下面是一些抽象类,最后是具体实现类,常见有ArrayList,LinedList,HashSet,LinkedHashSet, HashMap,LinkedHashMap等。
在这里插入图片描述

所有的集合框架都包含如下内容:

接口:是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象

实现(类):是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。

算法:是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。

数组和集合的比较

数组不是面向对象的,存在明显的缺陷,集合弥补了数组的缺点,比数组更灵活更实用,而且不同的集合框架类可适用不同场合。如下:
1:数组能存放基本数据类型和对象,而集合类存放的都是对象的引用,而非对象本身!
2:数组容易固定无法动态改变,集合类容量动态改变。
3:数组无法判断其中实际存有多少元素,length只告诉了数组的容量,而集合的size()可以确切知道元素的个数
4:集合有多种实现方式和不同适用场合,不像数组仅采用顺序表方式
5:集合以类的形式存在,具有封装、继承、多态等类的特性,通过简单的方法和属性即可实现各种复杂操作,大大提高了软件的开发效率

Collection

List

List 接口存储一组不唯一,有序(插入顺序)的对象

ArrayList

1、ArrayList 定义
ArrayList 是一个用数组实现的集合,支持随机访问,元素有序且可以重复。

在这里插入图片描述
①、实现 RandomAccess 接口
这是一个标记接口,一般此标记接口用于 List 实现,以表明它们支持快速(通常是恒定时间)的随机访问。该接口的主要目的是允许通用算法改变其行为,以便在应用于随机或顺序访问列表时提供良好的性能。
②、实现 Cloneable 接口
③、实现 Serializable 接口
④、实现 List 接口
2、字段属性
3、构造函数
  注意:根据默认构造函数创建的集合,ArrayList list = new ArrayList();此时集合长度是0.
4、添加元素
扩容的核心方法就是调用前面我们讲过的Arrays.copyOf 方法,创建一个更大的数组,然后将原数组元素拷贝过去即可。
对于 ArrayList 集合添加元素,我们总结一下:

①、当通过 ArrayList() 构造一个空集合,初始长度是为0的,第 1 次添加元素,会创建一个长度为10的数组,并将该元素赋值到数组的第一个位置。

②、第 2 次添加元素,集合不为空,而且由于集合的长度size+1是小于数组的长度10,所以直接添加元素到数组的第二个位置,不用扩容。

③、第 11 次添加元素,此时 size+1 = 11,而数组长度是10,这时候创建一个长度为10+10*0.5 = 15 的数组(扩容1.5倍),然后将原数组元素引用拷贝到新数组。并将第 11 次添加的元素赋值到新数组下标为10的位置。

④、第 Integer.MAX_VALUE - 8 = 2147483639,然后 2147483639%1.5=1431655759(这个数是要进行扩容) 次添加元素,为了防止溢出,此时会直接创建一个 1431655759+1 大小的数组,这样一直,每次添加一个元素,都只扩大一个范围。

⑤、第 Integer.MAX_VALUE - 7 次添加元素时,创建一个大小为 Integer.MAX_VALUE 的数组,在进行元素添加。

⑥、第 Integer.MAX_VALUE + 1 次添加元素时,抛出 OutOfMemoryError 异常。

注意:能向集合中添加 null 的,因为数组可以有 null 值存在。
5、删除元素
  ①、根据索引删除元素
remove(int index) 方法表示删除索引index处的元素,首先通过 rangeCheck(index) 方法判断给定索引的范围,超过集合大小则抛出异常;接着通过 System.arraycopy 方法对数组进行自身拷贝。
  ②、直接删除指定元素
remove(Object o)方法是删除第一次出现的该元素。然后通过System.arraycopy进行数组自身拷贝。
6、修改元素
通过调用 set(int index, E element) 方法在指定索引 index 处的元素替换为 element。并返回原数组的元素。
7、查找元素
①、根据索引查找元素
②、根据元素查找索引
8、遍历集合
  ①、普通 for 循环遍历
  ②、迭代器 iterator
     注意:迭代器只能向后遍历,不能向前遍历,能够删除元素,但是不能新增元素
  ③、迭代器的变种 forEach
for(String str : list){
System.out.print(str + " ");
}
  ④、迭代器 ListIterator
相比于 Iterator 迭代器,这里的 ListIterator 多出了能向前迭代,以及能够新增元素。
9、SubList
public List subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
作用是返回从 fromIndex(包括) 开始的下标,到 toIndex(不包括) 结束的下标之间的元素视图.
如果对 subList 出来的集合进行修改或新增操作,那么原始集合也会发生同样的操作。
10、size()
  注意:返回集合的长度,而不是数组的长度,这里的 size 就是定义的全局变量。
11、isEmpty()
  返回 size == 0 的结果。
12、trimToSize()
该方法用于回收多余的内存。也就是说一旦我们确定集合不在添加多余的元素之后,调用 trimToSize() 方法会将实现集合的数组大小刚好调整为集合元素的大小。
  注意:该方法会花时间来复制数组元素,所以应该在确定不会添加元素之后在调用。

LinkedList

1、LinkedList 定义

LinkedList底层是通过双向链表实现的。所以,LinkedList和ArrayList之前的区别主要就是数组和链表的区别。
ArrayList和LinkedList的大致区别如下:

1.ArrayList是实现了基于动态数组的数据结构,LinkedList基于链表的数据结构。

2.对于随机访问get和set,ArrayList觉得优于LinkedList,因为LinkedList要移动指针。

3.对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。

1 public class LinkedList
2 extends AbstractSequentialList
3 implements List, Deque, Cloneable, java.io.Serializable
在这里插入图片描述
2、字段属性
//链表元素(节点)的个数
transient int size = 0;

/**
 *指向第一个节点的指针
 */
transient Node<E> first;

/**
 *指向最后一个节点的指针
 */
transient Node<E> last;

private static class Node {
E item;//实际存储的元素
Node next;//指向上一个节点的引用
Node prev;//指向下一个节点的引用

    //构造函数
    Node(Node<E> prev, E element, Node<E> next) {
        this.item = element;
        this.next = next;
        this.prev = prev;
    }
}

3、构造函数
public LinkedList() {
}
public LinkedList(Collection<? extends E> c) {
this();
addAll©;
}
4、添加元素
  ①、addFirst(E e)  将指定元素添加到链表头
  ②、addLast(E e)和add(E e)  将指定元素添加到链表尾
  ③、add(int index, E element)  将指定的元素插入此列表中的指定位置
  ④、addAll(Collection<? extends E> c)  按照指定集合的​​迭代器返回的顺序,将指定集合中的所有元素追加到此列表的末尾
5、删除元素
  ①、remove()和removeFirst()  从此列表中移除并返回第一个元素
  ②、removeLast()  从该列表中删除并返回最后一个元素
  ③、remove(int index)  删除此列表中指定位置的元素
  ④、remove(Object o)  如果存在,则从该列表中删除指定元素的第一次出现
6、修改元素
  通过调用 set(int index, E element) 方法,用指定的元素替换此列表中指定位置的元素。
7、查找元素
  ①、getFirst()  返回此列表中的第一个元素

②、getLast()  返回此列表中的最后一个元素
  ③、get(int index)  返回指定索引处的元素
  ④、indexOf(Object o)  返回此列表中指定元素第一次出现的索引,如果此列表不包含元素,则返回-1。
8、遍历集合
  ①、普通 for 循环
  ②、迭代器
9、迭代器和for循环效率差异
  普通for循环:每次遍历一个索引的元素之前,都要访问之间所有的索引。
在这里插入图片描述
  迭代器:每次访问一个元素后,都会用游标记录当前访问元素的位置,遍历一个元素,记录一个位置。
在这里插入图片描述

Vector

向量类提供了三种构造方法:

public vector()
public vector(int initialcapacity,int capacityIncrement)
public vector(int initialcapacity)
使用第一种方法系统会自动对向量进行管理,若使用后两种方法,则系统将根据参数,initialcapacity设定向量对象的容量(即向量对象可存储数据的大小),当真正存放的数据个数超过容量时。系统会扩充向量对象存储容量。
参数capacityincrement给定了每次扩充的扩充值。当capacityincrement为0的时候,则每次扩充一倍,利用这个功能可以优化存储。
插入功能:
(1)public final synchronized void adddElement(Object obj)
将obj插入向量的尾部。obj可以是任何类型的对象。对同一个向量对象,亦可以在其中插入不同类的对象。但插入的应是对象而不是数值,所以插入数值时要注意将数组转换成相应的对象。
(2) public final synchronized void setElementAt(Object obj,int index)
将index处的对象设置成obj,原来的对象将被覆盖。
(3) public final synchronized void insertElementAt(Object obj,int index)
在index指定的位置插入obj,原来对象以及此后的对象依次往后顺延。
删除功能:
(1) public final synchronized void removeElement(Object obj)
从向量中删除obj,若有多个存在,则从向量头开始试,删除找到的第一个与obj相同的向量成员。
(2) public final synchronized void removeAllElement();
删除向量所有的对象
(3) public fianl synchronized void removeElementAt(int index)
删除index所指的地方的对象
查询搜索功能:
(1)public final int indexOf(Object obj)
从向量头开始搜索obj,返回所遇到的第一个obj对应的下标,若不存在此obj,返回-1.
(2)public final synchronized int indexOf(Object obj,int index)
从index所表示的下标处开始搜索obj.
(3)public final int lastindexOf(Object obj)
从向量尾部开始逆向搜索obj.
(4)public final synchornized int lastIndex(Object obj,int index)
从index所表示的下标处由尾至头逆向搜索obj.
(5)public final synchornized firstElement()
获取向量对象中的首个obj
(6)public final synchornized Object lastElement()
获取向量对象的最后一个obj
其他功能:
(1) public final int size();
此方法用于获取向量元素的个数。它们返回值是向量中实际存在的元素个数,而非向量容量。可以调用方法capacity()来获取容量值。
(2) public final synchronized void setSize(int newsize);
此方法用来定义向量的大小,若向量对象现有成员个数已经超过了newsize的值,则超过部分的多余元素会丢失。
程序中定义Enumeration类的一个对象Enumeration是java.util中的一个接口类,
(3) public final synchronized Enumeration elements();
此方法将向量对象对应到一个枚举类型。java.util包中的其他类中也都有这类方法,以便于用户获取对应的枚举类型。

3个具体实现类的相关区别如下:
1.ArrayList是最常用的List实现类,内部是通过数组实现的,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要讲已经有数组的数据复制到新的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
2.Vector与ArrayList一样,也是通过数组实现的,不同的是它支持线程的同步,即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢。
3.LinkedList是用链表结构存储数据的,很适合数据的动态插入和删除,随机访问和遍历速度比较慢。另外,他还提供了List接口中没有定义的方法,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
4.vector是线程(Thread)同步(Synchronized)的,所以它也是线程安全的,而Arraylist是线程异步(ASynchronized)的,是不安全的。如果不考虑到线程的安全因素,一般用Arraylist效率比较高。
5.如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist增长率为目前数组长度的50%.如过在集合中使用数据量比较大的数据,用vector有一定的优势。
6.如果查找一个指定位置的数据,vector和arraylist使用的时间是相同的,都是0(1),这个时候使用vector和arraylist都可以。而如果移动一个指定位置的数据花费的时间为0(n-i)n为总长度,这个时候就应该考虑到使用Linkedlist,因为它移动一个指定位置的数据所花费的时间为0(1),而查询一个指定位置的数据时花费的时间为0(i)。
6.ArrayList 和Vector是采用数组方式存储数据,此数组元素数大于实际存储的数据以便增加和插入元素,
都允许直接序号索引元素,但是插入数据要设计到数组元素移动 等内存操作,所以索引数据快插入数据慢,
Vector由于使用了synchronized方法(线程安全)所以性能上比ArrayList要差
,LinkedList使用双向链表实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入数度较快!
7.笼统来说:LinkedList:增删改快
ArrayList:查询快(有索引的存在)

Set

Set:注重独一无二的性质,该体系集合可以知道某物是否已近存在于集合中,不会存储重复的元素
Set 接口存储一组唯一,无序的对象

HashSet

1 HashSet概述
特点:作为Set集合的一种,首先是无序的,不可重复的;允许存放null值;底层封装HashMap;实现是不同步的,线程不安全;
常用构造:
public HashSet() :构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。
常用方法:
1)添加功能
boolean add(E e) : 如果此 set 中尚未包含指定元素,则添加指定元素
2)判断功能
boolean isEmpty(): 如果此 set 不包含任何元素,则返回 true。
boolean contains(Object o): 如果此列表中包含指定的元素,则返回 true
3)获取功能
int size() : 返回此 set 中的元素的数量(set 的容量)。
4)删除功能
void clear() :移除此列表中的所有元素。注意:此方法比较暴力,一般不使用。
boolean remove(Object o):如果指定元素存在于此 set 中,则将其移除。
5)迭代器功能
public Iterator iterator() 返回对此 set 中元素进行迭代的迭代器。返回元素的顺序并不是特定的。

LinkedHashSet

LinkedHashSet的功能与HashSet类似,毕竟是其子类。
有一个重要的区别:LinkedHashSet返回的元素顺序是可以预测的,即元素添加到集合的顺序。
LinkedHashSet 是 HashSet 的子类,其插入性能略低于 HashSet,但在迭代访问 Set 里的全部元素时有很好的性能
该功能可以用来快速查找并判断集合中是否包含指定对象,或者用于检索元素并按照元素的添加顺序返回元素

TreeSet
  TreeSet它是线程不安全的

向TreeSet中添加的元素必须是同一个类的
可以按照添加进集合中的元素的指定的顺序遍历。像String,包装类等默认按照从小到大的顺序遍历
当向TreeSet中添加自定义类的对象时,有两种排序方法:①自然排序②定制排序
自然排序:要求自定义类实现java.lang.Comparable接口并重写其compareTo(Object obj)的抽象方法在此方法中,指明按照自定义类的哪个属性进行排序
向TreeSet中添加元素时,首先按照compareTo()进行比较,一旦返回0,虽然仅是两个对象的此属性值相同,但是程序会认为这两个对象是相同的,进而后一个对象就不能添加进来
TreeSet集合排序的两种方式:

一,让元素自身具备比较性。
也就是元素需要实现Comparable接口,覆盖compareTo 方法。
这种方式也作为元素的自然排序,也可称为默认排序。

二,让容器自身具备比较性,自定义比较器。
需求:当元素自身不具备比较性,或者元素自身具备的比较性不是所需的。
那么这时只能让容器自身具备。
定义一个类实现Comparator 接口,覆盖compare方法。
并将该接口的子类对象作为参数传递给TreeSet集合的构造函数。
当Comparable比较方式,及Comparator比较方式同时存在,以Comparator比较方式为主。

看到array,就要想到角标。
看到link,就要想到first,last。
看到hash,就要想到hashCode,equals.
看到tree,就要想到两个接口。Comparable,Comparator。

Queue

Queue: 基本上,一个队列就是一个先入先出(FIFO)的数据结构
Queue接口与List、Set同一级别,都是继承了Collection接口。LinkedList实现了Deque接 口。

在这里插入图片描述
以下略

Map

我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同,如下图。
Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。
Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值。
Collection中的集合称为单列集合,Map中的集合称为双列集合。
需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。
Map中常用的集合为HashMap集合、LinkedHashMap集合。

HashMap

1.哈希表
Hash表也称为散列表,也有直接译作哈希表,Hash表是一种根据关键字值(key - value)而直接进行访问的数据结构。
ArrayList 集合和 LinkedList ,如果我们要查找这两个集合中的某个元素,通常是通过遍历整个集合,需要O(N)的时间级。
在这里插入图片描述
如果是哈希表,它是通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表,只需要O(1)的时间级。
在这里插入图片描述
多个 key 通过散列函数会得到相同的值,这时候怎么办?
第一种是开放地址法,当我们遇到冲突了,这时候通过另一种函数再计算一遍,得到相应的映射关系。比如对于汉语字典,一个字 “余”,拼音是“yu”,我们将其放在页码为567(假设在该位置),这时候又来了一个汉字“于”,拼音也是“yu”,那么这时候我们要是按照转换规则,也得将其放在页码为567的位置,但是我们发现这个页码已经被占用了,这时候怎么办?我们可以在通过另一种函数,得到的值加1。那么汉字"于"就会被放在576+1=577的位置。
第二种是链地址法,我们可以将字典的每一页都看成是一个子数组或者子链表,当遇到冲突了,直接往当前页码的子数组或者子链表里面填充即可。那么我们进行同音字查找的时候,可能需要遍历其子数组或者子链表。
2、什么是 HashMap?
HashMap<K,V>:存储数据采用的哈希表结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
HashMap 是由 数组+链表+红黑树构成。
在这里插入图片描述
 HashMap 是一个散列表,它存储的内容是键值对(key-value)映射,而且 key 和 value 都可以为 null。
1 public class HashMap<K,V> extends AbstractMap<K,V>
2 implements Map<K,V>, Cloneable, Serializable {
在这里插入图片描述
  ①、Node<K,V>[] table

我们说 HashMap 是由数组+链表+红黑树组成,这里的数组就是 table 字段。后面对其进行初始化长度默认是 DEFAULT_INITIAL_CAPACITY= 16。而且 JDK 声明数组的长度总是 2的n次方(一定是合数),为什么这里要求是合数,一般我们知道哈希算法为了避免冲突都要求长度是质数,这里要求是合数,下面在介绍 HashMap 的hashCode() 方法(散列函数),我们再进行讲解。

②、size

集合中存放key-value 的实时对数。

③、loadFactor

装载因子,是用来衡量 HashMap 满的程度,计算HashMap的实时装载因子的方法为:size/capacity,而不是占用桶的数量去除以capacity。capacity 是桶的数量,也就是 table 的长度length。

默认的负载因子0.75 是对空间和时间效率的一个平衡选择,建议大家不要修改,除非在时间和空间比较特殊的情况下,如果内存空间很多而又对时间效率要求很高,可以降低负载因子loadFactor 的值;相反,如果内存空间紧张而对时间效率要求不高,可以增加负载因子 loadFactor 的值,这个值可以大于1。

④、threshold

计算公式:capacity * loadFactor。这个值是当前已占用数组长度的最大值。过这个数目就重新resize(扩容),扩容后的 HashMap 容量是之前容量的两倍
注意:Map接口中的集合都有两个泛型变量<K,V>,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量<K,V>的数据类型可以相同,也可以不同。
5、构造函数
6、确定哈希桶数组索引位置
7、添加元素
8、扩容机制
9、删除元素
10、查找元素
11、遍历元素

12、总结
  ①、基于JDK1.8的HashMap是由数组+链表+红黑树组成,当链表长度超过 8 时会自动转换成红黑树,当红黑树节点个数小于 6 时,又会转化成链表。相对于早期版本的 JDK HashMap 实现,新增了红黑树作为底层数据结构,在数据量较大且哈希碰撞较多时,能够极大的增加检索的效率。
  ②、允许 key 和 value 都为 null。key 重复会被覆盖,value 允许重复。
  ③、非线程安全
  ④、无序(遍历HashMap得到元素的顺序不是按照插入的顺序)

LinkedHashMap

1、LinkedHashMap 定义
  LinkedHashMap 是基于 HashMap 实现的一种集合,具有 HashMap 集合上面所说的所有特点,除了 HashMap 无序的特点,LinkedHashMap 是有序的,因为 LinkedHashMap 在 HashMap 的基础上单独维护了一个具有所有数据的双向链表,该链表保证了元素迭代的顺序。
  所以我们可以直接这样说:LinkedHashMap = HashMap + LinkedList。LinkedHashMap 就是在 HashMap 的基础上多维护了一个双向链表,用来保证元素迭代顺序
2、字段属性
3、构造函数
4、添加元素
5、删除元素
6、查找元素
7、遍历元素
8、迭代器
9、总结
在这里插入图片描述
  去掉红色和蓝色的虚线指针,其实就是一个HashMap。

TreeMap

1、TreeMap 定义
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
  TreeMap 首先继承了 AbstractMap 抽象类,表示它具有散列表的性质,也就是由 key-value 组成。
  其次 TreeMap 实现了 NavigableMap 接口,该接口支持一系列获取指定集合的导航方法,比如获取小于指定key的集合。
  最后分别实现 Serializable 接口以及 Cloneable 接口,分别表示支持对象序列化以及对象克隆。
2、字段定义
  ①、Comparator
  ②、Entry
  ③、size
  ④、modCount
  ⑤、红黑树常量
3、构造函数
  ①、无参构造函数
  ②、带比较器的构造函数
  ③、构造包含指定map集合的元素
  ④、带 SortedMap的构造函数
4、添加元素
5、删除元素
  ①、根据key删除
  删除节点分为四种情况:

1、根据key没有找到该节点:也就是集合中不存在这一个节点,直接返回null即可。

2、根据key找到节点,又分为三种情况:

①、待删除节点没有子节点,即为叶子节点:直接删除该节点即可。

②、待删除节点只有一个子节点:那么首先找到待删除节点的子节点,然后删除该节点,用其唯一子节点顶替该节点。

③、待删除节点有两个子节点:首先找到该节点的中序后继节点,然后把这个后继节点的内容复制给待删除节点,然后删除该中序后继节点,删除过程又转换成前面①、②两种情况了,这里主要是找到中序后继节点,相当于待删除节点的一个替身
6、查找元素
  ①、根据key查找
7、遍历元素

附:map 遍历的四种方法

public static void main(String[] args) {


  Map<String, String> map = new HashMap<String, String>();
  map.put("1", "value1");
  map.put("2", "value2");
  map.put("3", "value3");
  
  //第一种:普遍使用,二次取值
  System.out.println("通过Map.keySet遍历key和value:");
  for (String key : map.keySet()) {
   System.out.println("key= "+ key + " and value= " + map.get(key));
  }
  
  //第二种
  System.out.println("通过Map.entrySet使用iterator遍历key和value:");
  Iterator<Map.Entry<String, String>> it = map.entrySet().iterator();
  while (it.hasNext()) {
   Map.Entry<String, String> entry = it.next();
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }
  
  //第三种:推荐,尤其是容量大时
  System.out.println("通过Map.entrySet遍历key和value");
  for (Map.Entry<String, String> entry : map.entrySet()) {
   System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
  }

  //第四种
  System.out.println("通过Map.values()遍历所有的value,但不能遍历key");
  for (String v : map.values()) {
   System.out.println("value= " + v);
  }
 }

如何选择?

1、容器类和Array的区别、择取

  • 容器类仅能持有对象引用(指向对象的指针),而不是将对象信息copy一份至数列某位置。
  • 一旦将对象置入容器内,便损失了该对象的型别信息。
    2、
  • 在各种Lists中,最好的做法是以ArrayList作为缺省选择。当插入、删除频繁时,使用LinkedList();
    Vector总是比ArrayList慢,所以要尽量避免使用。
  • 在各种Sets中,HashSet通常优于TreeSet(插入、查找)。只有当需要产生一个经过排序的序列,才用TreeSet。
    TreeSet存在的唯一理由:能够维护其内元素的排序状态。
  • 在各种Maps中
    HashMap用于快速查找。
  • 当元素个数固定,用Array,因为Array效率是最高的。
    结论:最常用的是ArrayList,HashSet,HashMap,Array。而且,我们也会发现一个规律,用TreeXXX都是排序的。

注意:
1、Collection没有get()方法来取得某个元素。只能通过iterator()遍历元素。
2、Set和Collection拥有一模一样的接口。
3、List,可以通过get()方法来一次取出一个元素。使用数字来选择一堆对象中的一个,get(0)…。(add/get)
4、一般使用ArrayList。用LinkedList构造堆栈stack、队列queue。
5、Map用 put(k,v) / get(k),还可以使用containsKey()/containsValue()来检查其中是否含有某个key/value。
HashMap会利用对象的hashCode来快速找到key。

  • hashing
    哈希码就是将对象的信息经过一些转变形成一个独一无二的int值,这个值存储在一个array中。
    我们都知道所有存储结构中,array查找速度是最快的。所以,可以加速查找。
    发生碰撞时,让array指向多个values。即,数组每个位置上又生成一个梿表。
    6、Map中元素,可以将key序列、value序列单独抽取出来。
    使用keySet()抽取key序列,将map中的所有keys生成一个Set。
    使用values()抽取value序列,将map中的所有values生成一个Collection。
    为什么一个生成Set,一个生成Collection?那是因为,key总是独一无二的,value允许重复。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值