- 前言
- 一、学习目标
- 二、集合类
- 三、Collection接口
- 四、List集合
- 五、Set集合
- 六、Map集合
- 七、HashMap
- 八、LinkedHashMap
- 九、TreeMap
- 十、HashTable
- 十一、Properties
- 十二、Collections工具类
- 十三、Java集合面试题
- 一、Collection和Collections的区别?
- 二、List、Set、Map之间的区别?
- 三、ArrayList和Vector的区别?
- 四、HashMap和Hashtable的区别?
- 五、Set里面的元素是不能重复的,那么是用什么来区分重复与否?是用==还是equals()?
- 六、说出ArrayList,LinkedList的存储性能和特性?
- 七、Enumeration和Iterator接口的区别?
- 八、ListIterator有什么特点?
- 九、并发集合类是什么?
- 十、Java中HashMap的key值要是为类对象则该类需要满足什么条件?
- 十一、与Java集合框架相关有哪些最好的实践?
- 十二、ArrayList集合加入一万条数据,应该怎么提高效率?
前言
关于对集合容器的大部分理解,后续慢慢增加,从为什么学习集合,集合有什么作用,到集合各种api的学习与理解。最后集合的相关面试题。
一、学习目标
一、Java集合学习指南
1.1 为什么要学习Java集合
- 方便对多个对象进行操作,将对象存储在容器中
1.2 如何学习Java集合
- 首先应该学习Java的基本用法,以及从它的整体去了解什么是集合
- 集合为了方便我们去操作多个对象给我们提供了一系列的API,我们要去学习如何使用这个方法
- 我么学习了这些基本的API去操作对象之后,应当从面向对象的角度去理解为什么要抽象出多个接口,以及这些接口的特性
- 我们可以总结出几个常用的实现类,并且了解这些实现类的数据结构,什么时候使用这些类
- 需要学习和了解的数据结构
1.3 学习进阶与面试
- Java集合是面试的重点 ,从基础用法到源码一步步深入。
下面取一些可能会问到的问题
- HashMap的数据结构是什么?他是怎么扩容的?底层有没有用红黑树?取Key Hash值是JDK源码是怎么实现的?为什么要这样做?简单作答一下
- HashMap是线程安全的吗?什么是线程安全?有什么更好的解决方案?那线程安全的HashMap是怎么实现的?简单作答一下
- HashSet是如何判断Key是重复的?简单作答一下你是《未来世界的幸存者》么?你是小贱
二、集合类
一、集合框架的概述
面向对象对事物的体现都是以对象的形式。为了方便对多个对象进行操作,那我们就需要将对象存储起来,Array数组储存对象有他的弊端,而java集合像一个容器,可以动态的将多个对象的引用放入容器中。
a) 数组在内存存储方面的特点:
i. 数组在初始化以后,长度就确定了
ii. 数据声明的类型,就决定了进行元素初始化时的类型
b) 数组存储对象的弊端:
i. 数组初始化以后,长度就不变了,不利于拓展
ii. 数组中提供的属性和方法少,不利于进行添加 ,删除,插入等操作,并且效率不高。同时无法直接获取存储元素的个数。
iii. 数组存储的数据是有序的,可以重复的 —à 存储数据的特点单一
Java集合可以用于存储数量不等的多个对象,还可以用于保存具有映射关系的关联数组。
二、集合的体系
2.1 Collection接口和Map接口
Collection接口:单列数据,定义了一组存储对象的方法的集合
- List:元素有序,可重复的集合
- Set:元素无序,不可重复的集合
- Map接口:双列数据,保存具有”KEY-VALUE”映射关系的集合
三、Collection接口
一、Collection介绍
1.1 Collection的结构
Collection接口是List,Map和Queue接口的父接口。该接口里面的方法均可用于操作List接口,Map接口,Queue接口。
JDK不提供该接口的任何直接实现,而是提供了更具体的子接口实现。
在Java5之前Java集合会丢失容器中所有对象的数据类型,将对象当成Object类型处理。从5.0之后,增加了泛型,Java集合可以记住容器中对象的数据类型。
1.2 Collection的由来
- 集合可以存储多个元素,但我们对多个元素也有不同的需求
- 多个元素,不能有相同的
- 多个元素,能够按照某个规则排序
- 针对不同的需求:java就提供了很多集合类,多个集合类的数据结构不同。但是,结构不重要,重要的是能够存储东西,能够判断,获取
- 把集合共性的内容不断往上提取,最终形成集合的继承体系——>Collection
1.3 Collection的基础功能

- 添加 add (Objecet obj )add(collertion c)
Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person(“Jerry”,20));
coll.add(new String(“Tom”));
coll.add(false);
- 获取元素的有效个数 int size()
- 清空集合 void clear()
- 是否包含空集合 Boolean isEmpty()
- 是否包含某元素 a) boolean contains(Object obj) 通过元素的equals()来判断是否相等b) boolean containsAll(Collection c) 拿两个集合的元素挨个比较,也是通过equals 来比较的。
- 删除 a) boolean remove(Object obj)通过equals()找到第一个元素 删除第一个元素b) boolean removeAll(Collection c) 取两个集合的差集
- 取两个集合的交集 boolean retainAll(Collection c)
- 集合是否相等 boolean equals(Collection c)
- 转成对象数组 Object[] toArray()
- 获取对象的哈希值 hashCode()
-
二、迭代器(Iterator)介绍
2.1 使用Iterator接口遍历集合元素
Iterator对象称为迭代器(设计模式的一种),主要用于遍历Collection集合中的元素。
- 提供一种方法访问容器对象中的各个元素,而又不需要暴露该对象的内部细节。迭代器模式就是为容器而生。
- Collection接口继承了Java.lang.iterable接口,该接口有一个Iterator()方法,所有继承了Collection接口的集合类都有一个Iterator()方法,用以返回一个实现了Iterator()方法的对象。
- Iterator仅用于遍历集合。Iterator本身并不具有承载对象的能力,如果需要创建Iterator对象,则必须有一个被迭代的对象。
- 集合对象每次调用Iterator()都会创建一个全新的迭代器对象。默认游标都在第一个元素之前。

在调用it.next()方法之前都要调用it.hasNext()进行检测。否则下一条记录无效。若直接调用next()方法,抛出NoSushElementException()异常。
2.2 迭代器的删除元素
- 迭代器可以删除集合中的元素 但是不是调用Collection的remove() 。是迭代器对象自己的remove()方法。
- 如果还未调用next()或在上一次调用 next 方法之后已经调用了 remove 方法, 再调用remove都会报IllegalStateException。
Iterator iterator = coll.iterator();
while (iterator.hasNext()){
Object next = iterator.next();<br /> if ("Tom".equals(next)){<br /> iterator.remove();<br /> }<br />}
2.3 foreach循环遍历集合
- Java5.0提供了foreach循环迭代访问集合和数组。
- 遍历操作不需要获取Collection或者数组的长度,无需使用索引访问元素。
- 遍历集合的底层调用Iterator完成操作。
- foreach还可以用来遍历数组。

- 判断foreach遍历数组的输出结果?
String[] str = new String[5];
for (String myStr : str) {
myStr = “atguigu”;
System.out.println(myStr);
}
for (int i = 0; i < str.length; i++) {
System.out.println(str[i]);
}
输出结果为atguigu atguigu atguigu atguigu atguigu null null null null null
因为foreach知识遍历数组,并不改变数组。
若是想要改变数组,则有下面的案例。使用普通for循环遍历并进行数组赋值操作。
for (int i = 0; i < str.length; i++) {
str[i] = i+”1”;
}
for (int i = 0; i < str.length; i++) {
System.out.println(str[i]);
}
三、List接口介绍
3.1 List接口概述
- 鉴于Java中数组存储数据的局限性,通常我们使用List来代替数组。
- List集合类中元素有序,可重复。集合中的每个元素都有其对应的顺序索引。
- List容器中的元素都有其对应的整数型的序号,我们可以通过序号存取容器中的元素。
- List接口常用实现类I. ArrayList 底层数据结构是数组。线程不安全。II. LinkedList 底层数据结构是链表。线程不安全。III. Vector 底层数据结构是数组。线程安全(过时)。
3.2 List接口方法
- 继承父接口的方法之外,List添加了根据索引操作集合中的元素。
- void add(int Index,Object ele) 在index位置中添加ele元素
- boolean addAll(int index,Collection eles) 在index位置中将所有的元素eles全部加入进来
- Object get(int index) 获取指定index位置元素
- int indexOf(Object obj) 返回obj在集合中首次出现的位置
- int lastIndexOf(Object obj) 返回obj 在当前集合中末次出现的位置
- Object remove(int index) 移除index位置上的元素并返回此元素
- Object set(int index,Object ele) 指定index位置上的元素为ele
- List subList(int fromIndex,int toIndex) 返回从fromIndex到toIndex的子集合
-
四、Set接口介绍
4.1 Set接口概述
set接口是Collection接口的子接口,set接口没有提供额外的方法。
- Set集合不允许包含相同的元素,如果添加相同的元素,则会添加失败。元素不可重复
Set判断两个对象是否相同不是使用==比较,而是使用equals()比较。
4.2 Set常用子类
HashSet集合
- 底层数据结构是哈希表(一个元素为链表的数组)
- TreeSet集合
- 底层数组结构是红黑树
- 保证元素的排序方式
- LinkedHashSet集合
- ArrayList是List接口主要实现类
- ArrayList线程不安全,查找效率高,并且可以存放null
底层是一个数组,可以实现动态增长,因为他又扩容这么一个机制。
1.2 ArrayList底层源码分析
jdk8中,ArrayList底层创建了一个Object[] elementData 的数组,默认大小为0的空数组。当我们使用它的时候,会自动创建一个大小为10的数组。每次add操作的时候,都会先检查是否需要扩容。默认情况下回扩容为原来的1.5倍,并将原有数组中的数据复制到新的数组中。扩容的方法grow() ,复制的方法copyOf()
- 而在jdk7中,底层是初始化一个大小为10的数组。后续再进行扩容。
- 实际上jdk7类似于单例中的饿汉式。jdk8类似于单例中的懒汉式,延迟了数组的创建,节省内存。
- 因为Arraylist拥有扩容这个概念,因此ArrayList是基于动态数组实现的,在增删时候需要数组的拷贝复制。
- 删除的时候并不会减少容量。
a) 结构示意图
b) 源码示意图介绍

二、 ArrayList和Vector的区别
- vector是jdk1.2中比较古老的集合实现类
- vector和Arraylist底层都是数组,区别就是同步(线程安全)
- 一般我们不考虑同步的情况下使用ArrayList.考虑同步的情况下使用Collections中的方法来实现同步。Collections.synchronizedList(new ArrayList(…))
- 这种情况下使用Collections的方法来实现同步浪费资源,有一个实现类copyOnWriteArrayList可以实现同步
- 还有另外一个区别,ArrayList在原来的基础上扩容0.5被,而Vector扩容一倍。
问:为什么Java不推荐使用Vector?
- 因为vector是线程安全的,所以效率低,这容易理解,类似StringBuffer
- Vector空间满了之后,扩容是一倍,而ArrayList仅仅是一半
- Vector分配内存的时候需要连续的存储空间,如果数据太多,容易分配内存失败
- 只能在尾部进行插入和删除操作,效率低
三、LinkedList分析
3.1 LinkedList介绍
- 底层的数据结构是双向链表,线程不安全
- 对于频繁的插入或者删除元素的操作。使用LinkedList,效率较高。
3.2 新增方法(了解)
```
void addFirst(Object obj)
• void addLast(Object obj)
• Object getFirst()
• Object getLast()
• Object removeFirst()
3.3 底层源码实现
- 数据结构a) 双向链表,内部没有声明数组。而是定义了Node类型的first和last,用于记录首末位置。同时定义内部类Node,作为LinkedList中保存数据的基本结构。b) Node除了保存数据,还定义了两个变量。i. prev变量记录前一个元素的位置。ii. next变量记录下一个元素的位置。
四、List集合总结
五、Set集合
一、HashSet分析
1.1 HashSet介绍
- HashSet按Hash算法来存储集合中的元素,因此具有很好的存储,查找,删除等功能。
- HashSet的特点
- 不能保证元素的顺序
- HashSet不是线程安全的
- 可以存储null
- HashSet是不允许存储相同的元素,判断两个元素是否相同,是通过两个对象的HashCode()方法来比较相等,并且两个对象的equals()方法返回值相等。
- 对于存放Set容器中的对象,对应的类一定要重写equals()方法和hashCode()方法,以实现对象相等规则,“相等的对象必须有相等的散列码”
-
1.2 HashSet存储过程
向HashSet集合中存储一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据hashCode值通过某种散列函数决定该对象再HashSet底层数组中的存储位置。
- 如果两个元素的hashCode()值相等,会继续调用equals()方法,如果equals()方法返回值为true,添加失败;如果为false,那么会保存该元素,但是该数组的位置已经有元素了,那么会通过链表的方式继续链接。
如果两个元素的equals()返回值相等,但他们的hashCode()返回值不相等,hashSet将会把他们存储再不同的位置,但依然可以添加成功。
1.3 重写hashCode()方法的基本原则
在程序运行时,同一个对象多次调用hashCode()方法应该返回相同的值。
- 当两个对象的equals()方法比较返回true时,这两个对象的hashCode()方法的返回值应该相同
- 对象中用作equals()方法比较的Field,都应该用来计算hashCode()值。
1.4 HashSet源码分析
 <br />从源码分析中我们可以看到操作HashSet实际上就是操作Hashmap,因此我们可以在学习到HashMap过后再来深究HashSet
二、LinkedHashSet分析
2.1 LinkedHashSet介绍
- 对象中用作equals()方法比较的Field,都应该用来计算hashCode()值。
- 当两个对象的equals()方法比较返回true时,这两个对象的hashCode()方法的返回值应该相同
- LinkedHashSet是HashSet的子类
- LinkedHashSet是根据元素的hashCode值来决定元素的存储位置,但他同时使用 双向链表维护元素的次序,这使得元素看起来是以插入顺序保存的。
- LinkedHashSet插入性能略低于HashSet,但在迭代访问Set里的全部元素时有很好的性能
-
2.2 LinkedList源码分析
a)底层数据结构图

三、TreeSet分析
3.1 TreeSet介绍
TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态。
-
3.2 红黑树认知
TreeSet和后面的TreeMap采用红黑树的存储结构
- 有序,查询速度比List快
3.3 TreeSet的两种排序
3.3.1 自然排序(默认)
- TreeSet会调用集合元素的compareTo(Object obj)方法来比较元素中间的大小,然后将集合元素按升序排列。
- 如果将一个对象添加到TreeSet时,则该对象必须实现Comparable接口
- 实现Comparable的类必须实现CompareTo(Object obj)方法,两个对象既通过compareTo(Object obj)方法的返回值来比较大小。
- Comparable的典型实现
- 向 TreeSet 中添加元素时,只有第一个元素无须比较compareTo()方法,后面添加的所有元素都会调用compareTo()方法进行比较。
- 因为只有相同类的两个实例才会比较大小,所以向 TreeSet 中添加的应该是同一个类的对象。
- 对于 TreeSet 集合而言,它判断两个对象是否相等的唯一标准是:两个对象通过 compareTo(Object obj) 方法比较返回值。
当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保 证该方法与compareTo(Object obj) 方法有一致的结果:如果两个对象通过 equals() 方法比较返回 true,则通过compareTo(Object obj) 方法比较应返回 0。 否则,让人难以理解
3.3.2 定制排序
TreeSet的自然排序要求元素所属的类实现Comparable接口,如果元素所属的没有实现Comparable接口,或不希望按照升序(默认情况)的方式排列元素或希望按照其它属性大小进行排序,则考虑使用定制排序。定制排序,通过Comparato接口来实现。需要重写compare(T o1,T o2)方法。
- 利用int compare(T o1,T o2)方法,比较o1和o2的大小:如果方法返回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示o1小于o2。
- 要实现定制排序,需要将实现Comparator接口的实例作为形参传递给TreeSet构造器。
- 此时,仍然只能向TreeSet中添加类型相同的对象。否则发生ClassCastException异常。
使用定制排序判断两个元素相等的标准是:通过Comparator比较两个元素返回了0。
六、Map集合
一、Map介绍
1.1 Map的概述
Map和Collection并列存在,用来保存具有映射关系的数据。
Map集合的特点 将键映射到值的对象,一个映射不能 包含重复的键,一个键最多只能映射到一个值
Map与Collection集合的区别:
添加、删除、修改操作:
- Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
- void putAll(Map m):将m中的所有key-value对存放到当前map中
- Object remove(Object key):移除指定key的key-value对,并返回value
- void clear():清空当前map中的所有数据
- 元素查询的操作:
- Object get(Object key):获取指定key对应的value
- boolean containsKey(Object key):是否包含指定的key
- boolean containsValue(Object value):是否包含指定的value
- int size():返回map中key-value对的个数
- boolean isEmpty():判断当前map是否为空
- boolean equals(Object obj):判断当前map和参数对象obj是否相等
- 元视图操作的方法:
- Set keySet():返回所有key构成的Set集合
- Collection values():返回所有value构成的Collection集合
- Set entrySet():返回所有key-value对构成的Set集合
二、散列表介绍
三、红黑树介绍
七、HashMap
一、HashMap介绍
- HashMap是map接口中使用频率最高的实现类
- 允许null键和null值,和set一样,不保证映射的顺序
- 所有key构成的集合是Set,:无序不可重复的。所以key所在的类要重写hashCode()和equals()
- 所有value构成 的集合是collection无序的,可以重复的。
- 一个key-value构成一个entry
- 所有entry构成的集合是Set:无序的,不可重复的。
HahMap判断两个key值相等的标准:两个key通过equals()返回为true,hashCode值也相等。
二、存储结构图
2.1 JDK7之前时数组+链表
2.2 JDK8是数组+链表+红黑树

当数组的某一个索引位置上的元素以链表形式存在的数据个数 > 8 且当前数组的长度 > 64时,此时此索引位置上的所数据改为使用红黑树存储。
从基本结构和实现上来说基本上都是相同的,都是实现Map接口
区别
- 同步性
- HashMap不是同步的
- Hashtable是同步的
- 如果想要同步的话可以使用ConcurrentHashMap
- 是否允许为null
- HashMap允许为null
- Hashtable不允许为null
- contains方法
- Hashtable有contains方法
- HashMap将其拆分为containsValue()和containsKey()
- 继承不同
- LinkedHashMap 是 HashMap 的子类
- 在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序
- 与LinkedHashSet类似,LinkedHashMap 可以维护 Map 的迭代顺序:迭代顺序与 Key-Value 对的插入顺序一致
二、类继承图
九、TreeMap
一、TreeMap介绍
- TreeMap存储 Key-Value 对时,需要根据 key-value 对进行排序。
- TreeMap 可以保证所有的 Key-Value 对处于有序状态。
- TreeSet底层使用红黑树结构存储数据
- TreeMap 的 Key 的排序: 自然排序:TreeMap 的所有的 Key 必须实现 Comparable 接口,而且所有 的 Key 应该是同一个类的对象,否则将会抛出 ClasssCastException 定制排序:创建 TreeMap 时,传入一个 Comparator 对象,该对象负责对 TreeMap 中的所有 key 进行排序。此时不需要 Map 的 Key 实现 Comparable 接口
TreeMap判断两个key相等的标准:两个key通过compareTo()方法或 者compare()方法返回0。
二、类继承图
十、HashTable
Hashtable是个古老的 Map 实现类,JDK1.0就提供了。不同于HashMap, Hashtable是线程安全的。
- Hashtable实现原理和HashMap相同,功能相同。底层都使用哈希表结构,查询速度快,很多情况下可以互用。
- 与HashMap不同,Hashtable 不允许使用 null 作为 key 和 value
- 与 HashMap一样,Hashtable 也不能保证其中 Key-Value 对的顺序
Hashtable判断两个key相等、两个value相等的标准,与HashMap一致。
十一、Properties
Properties 类是 Hashtable 的子类,该对象用于处理属性文件
- 由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key和 value 都是字符串类型
存取数据时,建议使用setProperty(String key,String value)方法和 getProperty(String key)方法
十二、Collections工具类
一、工具类介绍
Collections 是一个操作 Set、List 和 Map 等集合的工具类
Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作, 还提供了对集合对象设置不可变、对集合对象实现同步控制等方法
二、操作API
2.1 排序操作:(均为static方法)
reverse(List):反转 List 中元素的顺序
- shuffle(List):对 List 集合元素进行随机排序
- sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
- sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
swap(List,int, int):将指定 list 集合中的 i 处元素和 j
2.2 常用方法
查找、替换
Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
lObject max(Collection,Comparator):根据 Comparator 指定的顺序,返回
给定集合中的最大元素
- Object min(Collection)
- Object min(Collection,Comparator)
- int frequency(Collection,Object):返回指定集合中指定元素的出现次数
- void copy(List dest,List src):将src中的内容复制到dest中
- boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换list
- Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集 合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全 问题
十三、Java集合面试题
一、Collection和Collections的区别?
Collection是集合的一个接口(顶级接口),它提供了对集合对象进行基本操作的通用方法。
- Collection接口在Java类库中有很多具体的是实现。其作用是为各种集合提供一个最大化的统一操作方式。直接继承的接口有List和Map.Collections是集合类的一个工具类,提供了一系列的静态方法。用于对集合中的元素进行排序、搜索、线程安全等一系列操作。
二、List、Set、Map之间的区别?
| 比较 | List | Set | Map | | —- | —- | —- | —- | | 继承接口 | Collection | Collection | | | 常用实现类 | ArrayList,LinkedList, vector | HashSet,LinkedHashSet, TreeSet | HashTable, HashMap | | 常见方法 | | | | | 元素 | 可重复 | 不可重复 | 不可重复 | | 顺序 | 有序 | 无序 | | | 线程安全 | Vector安全 | | HashTable安全 |
三、ArrayList和Vector的区别?
共同点
- ArrayList都是有序的集合。底层都是数组,允许存储重复的和NULL值。
区别
- 同步性
- Vector是同步的
- ArrayList是不同步的
- 若是想要集合同步的话,我们也可以使用Collections 中的方法来实现同步ArrayList arraylist = Collections.synchronizedList(new AarrayList(…))
- 扩容性
- ArrayList扩容机制为扩大为原来的1.5倍,而Vector扩大为原来的两倍。
扩展 :为什么jdk不推荐使用Vector
从基本结构和实现上来说基本上都是相同的,都是实现Map接口
区别
- 同步性
- HashMap不是同步的
- Hashtable是同步的
- 如果想要同步的话可以使用ConcurrentHashMap
- 是否允许为null
- HashMap允许为null
- Hashtable不允许为null
- contains方法
- Hashtable有contains方法
- HashMap将其拆分为containsValue()和containsKey()
继承不同
ArrayList底层是数组,LinkedList底层是链表。
- ArrayList支持以角标索引出对应的元素,而LinkedList需要遍历出整个链表来搜索出对应的元素,因此 一般来说ArrayList的访问速度要比LinkedList的速度快
ArrayList底层数组,对于增加和删除需要通过复制和移动数组来实现。而LinkedList是双向链表增加和删除只需要通过移动指针来实现,消耗是很小的。因此 一般来说LinkedList的增删速度是要比ArrayList的速度快的
扩展 6.1
ArrayList的增删速度未必就比LinkedList慢。
- 如果增删都是在末尾来操作【每次调用的都是remove()和add()】,此时ArrayList就不需要移动和复制数组来进行操作了。如果数据量有百万级的时,速度是会比LinkedList要快的。(我测试过)
如果删除操作的位置是在中间。由于LinkedList的消耗主要是在遍历上,ArrayList的消耗主要是在移动和复制上(底层调用的是arraycopy()方法,是native方法)。
Enumeration是旧的迭代器,现在Iterator替代了它,他是被抛弃的迭代器
- 主要原因是Iterator比较安全,在集合遍历的时候,它会阻止其他线程去修改集合
区别有三点
ListIterator继承了Iterator接口,用来遍历List集合的元素
ListIterator可以实现双向遍历,添加元素,设置元素
九、并发集合类是什么?
Java1.5并发包(java.util.concurrent)包含线程安全集合类,允许在迭代时修改集合。
十、Java中HashMap的key值要是为类对象则该类需要满足什么条件?
因为HashMap的key是Set类型存储的,因此该类必须重写equals()和HashCode()
- 从源码可以得知,在插入元素的时候是先算出该对象的hashCode。如果hashcode相等话的。那么表明该对象是存储在同一个位置上的。
- 如果调用equals()方法,两个key相同,则替换元素
- 如果调用equals()方法,两个key不相同,则说明该hashCode仅仅是碰巧相同,此时是散列冲突,将新增的元素放在桶子上
- 一般来说,我们会认为:只要两个对象的成员变量的值是相等的,那么我们就认为这两个对象是相等的!因为,Object底层比较的是两个对象的地址,而对我们开发来说这样的意义并不大~这也就为什么我们要重写equals()方法
- 重写了equals()方法,就要重写hashCode()的方法。因为equals()认定了这两个对象相同,而同一个对象调用hashCode()方法时,是应该返回相同的值的!
十一、与Java集合框架相关有哪些最好的实践?
- 根据需要确定集合的类型。如果是单列的集合,我们考虑用Collection下的子接口ArrayList和Set。如果是映射,我们就考虑使用Map~
- 确定完我们的集合类型,我们接下来确定使用该集合类型下的哪个子类~我认为可以简单分成几个步骤:
- 是否需要同步
- 去找线程安全的集合类使用
- 迭代时是否需要有序(插入顺序有序)
- 去找Linked双向列表结构的
- 是否需要排序(自然顺序或者手动排序)
- 去找Tree红黑树类型的(JDK1.8)
- 是否需要同步
- 估算存放集合的数据量有多大,无论是List还是Map,它们实现动态增长,都是有性能消耗的。在初始集合的时候给出一个合理的容量会减少动态增长时的消耗~
- 使用泛型,避免在运行时出现ClassCastException
- 尽可能使用Collections工具类,或者获取只读、同步或空的集合,而非编写自己的实现。它将会提供代码重用性,它有着更好的稳定性和可维护性
十二、ArrayList集合加入一万条数据,应该怎么提高效率?
ArrayList的默认初始容量为10,要插入大量数据的时候需要不断扩容,而扩容是非常影响性能的。因此,现在明确了10万条数据了,我们可以直接在初始化的时候就设置ArrayList的容量!



