Java 集合框架提供了一套性能优良,使用方便的接口和类,java集合框)架位于java.util包中, 所以当使用集合框架的时候需要进行导包。
文章目录
- 一、Java集合框架体系
- 二、常用接口及方法
- 三、Collections工具类 —— 常用算法
- 四、Arrays类(数组)实用方法
- 五、遍历Collection
- 六、Map接口及其遍历
- 七、常见面试题
- 1. java 容器都有哪些?
- 2. Collection 和 Collections 有什么区别?
- 3. List、Set、Map 之间的区别是什么?
- 4. HashMap 和 HashTable 有什么区别?
- 5. 如何决定使用 HashMap 还是 TreeMap?
- 6. 说一下 HashMap 的实现原理?
- 7. 说一下 HashSet 的实现原理?
- 8. ArrayList 和 LinkedList 的区别是什么?
- 9. 如何实现数组Array 和 List 之间的转换?
- 10. ArrayList 和 Vector 的区别是什么?
- 11. 数组Array 和 集合ArrayList 有何区别?
- 12. 在 Queue 中 poll()和 remove()有什么区别?
- 13. 哪些集合类是线程安全的?
- 14. 迭代器 Iterator 是什么?
- 15. Iterator 怎么使用?有什么特点?
- 16. Iterator 和 ListIterator 有什么区别?
一、Java集合框架体系
- 接口 :是代表集合的抽象数据类型。例如 Collection、List、Set、Map 等。之所以定义多个接口,是为了以不同的方式操作集合对象
- 实现(类) :是集合接口的具体实现。从本质上讲,它们是可重复使用的数据结构,例如:ArrayList、LinkedList、HashSet、HashMap。
- 算法 :是实现集合接口的对象里的方法执行的一些有用的计算,例如:搜索和排序。这些算法被称为多态,那是因为相同的方法可以在相似的接口上有着不同的实现。
二、常用接口及方法
1. Collection接口及常用方法:
Collection 接口 Collection 是最基本的集合接口,一个 Collection 代表一组 Object,即 Collection 的元素, 不提供直接继承自Collection的类,只提供继承于的子接口(如List和set)。Collection 接口存储一组不唯一,无序 的对象。
- 查询方法
- 修改方法
2. Set接口(集合)
Set 具有与 Collection 完全一样的接口,只是行为上不同,Set 不保存重复的元素 。Set 接口存储一组唯一,无序 的对象。
- 实现Set接口的类:
- SortedSet 接口
3. List接口
List接口是一个有序 的 Collection,使用此接口能够精确的控制每个元素插入的位置,能够通过索引(元素在List中位置,类似于数组的下标)来访问List中的元素,第一个元素的索引为 0,而且允许有相同的元素 。List 接口存储一组不唯一,有序(插入顺序)的对象。
- 实现List接口的类
- Set和List的区别
- Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
- Set检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变 (实现类有HashSet,TreeSet)。
- List和数组类似,可以动态增长,根据实际存储的数据的长度自动增长List的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变 (实现类有ArrayList,LinkedList,Vector) 。
4. Queue接口(队列)
- 实现Queue接口的类
5. Map接口
Map 接口存储一组键值对象,提供key(键)到value(值)的映射。不能有重复的关键字 ,每个关键字最多能够映射到一个值。声明时可以带有两个参数,Map<K, V> ,K表示关键字的类型,V表示值的类型。
- Map接口及其子接口实现
- SortedMap 继承于 Map,使 Key 保持在升序排列。
- 实现Map接口的常用类——HashMap, TreeMap
三、Collections工具类 —— 常用算法
1. 排序算法 sort()
2. 洗牌算法 shuffle()
与 sort() 算法正好相反,用于打乱元素
3. 常规数据处理算法
4. 二分查找算法binarySearch()
5. 寻找最值
四、Arrays类(数组)实用方法
- java.utils.Arrays
- example: 数组的填充和复制
- 基于动态数组 的类型 Vector(遗留类型)、ArrayList(效率更高)
五、遍历Collection
- 通过 Enumeration 或 Iterator 接口遍历集合
- example:
public class Test{
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("HAHAHAHA");
// 使用迭代器进行相关遍历
Iterator<String> ite=list.iterator();
while(ite.hasNext())
System.out.println(ite.next());
}
}
- 增强for循环遍历集合
public class Test{
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("HAHAHAHA");
//使用 For-Each 遍历 List
for (String str : list) {
System.out.println(str);
}
}
- 通过聚集操作遍历集合
六、Map接口及其遍历
- 查询方法
- 修改方法
- 两个常用类HashTable(老版本)、HashMap
遍历Map
import java.util.*;
public class Test{
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. java 容器都有哪些?
常用容器的图录:
2. Collection 和 Collections 有什么区别?
java.util.Collection
是一个集合接口(集合类的一个顶级接口)。它提供了对集合对象进行基本操作的通用接口方法。Collection接口在Java 类库中有很多具体的实现。Collection接口的意义是为各种具体的集合提供了最大化的统一操作方式,其直接继承接口有List与Set。
Collections
则是集合类的一个工具类/帮助类,其中提供了一系列静态方法,用于对集合中元素进行排序、搜索以及线程安全等各种操作。 ex: Collections.shuffle()
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/*
* 集合操作的工具类
* Collections
*/
public class CollectionsDemo {
public static void main(String[] args) {
function();
function_1();
function_2();
}
/*
* Collections.shuffle方法
* 对List集合中的元素,进行随机排列
*/
public static void function_2(){
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(5);
list.add(9);
list.add(11);
list.add(8);
list.add(10);
list.add(15);
list.add(20);
System.out.println(list);
//调用工具类方法shuffle对集合随机排列
Collections.shuffle(list);
System.out.println(list);
}
/*
* Collections.binarySearch静态方法
* 对List集合进行二分搜索,方法参数,传递List集合,传递被查找的元素
*/
public static void function_1(){
List<Integer> list = new ArrayList<Integer>();
list.add(1);
list.add(5);
list.add(8);
list.add(10);
list.add(15);
list.add(20);
//调用工具类静态方法binarySearch
int index = Collections.binarySearch(list, 16);
System.out.println(index);
}
/*
* Collections.sort静态方法
* 对于List集合,进行升序排列
*/
public static void function(){
//创建List集合
List<String> list = new ArrayList<String>();
list.add("ewrew");
list.add("qwesd");
list.add("Qwesd");
list.add("bv");
list.add("wer");
System.out.println(list);
//调用集合工具类的方法sort
Collections.sort(list);
System.out.println(list);
}
}
3. List、Set、Map 之间的区别是什么?
4. HashMap 和 HashTable 有什么区别?
-
HashMap把Hashtable的
contains方法
(判断Hashtable是否包含“值(value)) 去掉了,改成containsValue
和containsKey
,因为contains方法容易让人引起误解。HashTable则保留了contains,containsValue和containsKey三个方法,其中contains和containsValue功能相同。
-
HashTable是同步的,而HashMap是非同步的,效率上逼HashTable要高。
-
HashMap是Hashtable的轻量级实现(非线程安全的实现),他们都完成了Map接口,主要区别在于HashMap允许空(null)键值(key), 由于非线程安全,在只有一个线程访问的情况下,效率要高于Hashtable。
5. 如何决定使用 HashMap 还是 TreeMap?
-
对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。
-
需要对一个有序的key集合进行遍历,TreeMap是更好的选择。
6. 说一下 HashMap 的实现原理?
-
HashMap概述: HashMap是基于哈希表的Map接口的非同步实现。此实现提供所有可选的映射操作,并允许使用null值和null键。此类不保证映射的顺序,特别是它不保证该顺序恒久不变。
-
HashMap的数据结构: 在java编程语言中,最基本的结构就是两种,一个是数组,另外一个是模拟指针(引用),所有的数据结构都可以用这两个基本结构来构造的,HashMap也不例外。HashMap实际上是一个“链表散列”的数据结构,即数组和链表的结合体。
-
当我们往Hashmap中put元素时,首先根据key的hashcode重新计算hash值,根绝hash值得到这个元素在数组中的位置(下标),如果该数组在该位置上已经存放了其他元素 (出现冲突), 那么在这个位置上的元素将以链表的形式存放,新加入的放在链头, 最先加入的放入链尾. 如果数组中该位置没有元素,就直接将该元素放到数组的该位置上。
-
需要注意Jdk 1.8中对HashMap的实现做了优化,当链表中的节点数据超过八个之后,该链表会转为红黑树来提高查询效率,从原来的O(n)到O(logn)
7. 说一下 HashSet 的实现原理?
-
HashSet底层由HashMap实现, 跟HashMap一样,都是一个存放链表的数组。
-
HashSet的值存放于HashMap的key上,不允许有重复元素
-
HashMap的value统一为PRESENT,
private static final Object PRESENT = new Object()
8. ArrayList 和 LinkedList 的区别是什么?
- 最明显的区别是:
ArrrayList底层的数据结构是数组,支持随机访问,
而 LinkedList 的底层数据结构是双向循环链表,不支持随机访问。 - 使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。
9. 如何实现数组Array 和 List 之间的转换?
-
List转换成为数组:调用ArrayList的toArray方法。
-
数组转换成为List:调用Arrays的asList方法。
10. ArrayList 和 Vector 的区别是什么?
- ArrayList 和 Vector是采用 数组 方式存储数据,它允许对元素进行快速随机访问。数组的缺点是每个元素之间不能有间隔,当数组大小不满足时需要增加存储能力,就要将已经有数组的数据复制到新的更大的存储空间中。当从ArrayList的中间位置插入或者删除元素时,需要对数组进行复制、移动、代价比较高。因此,它适合随机查找和遍历,不适合插入和删除。
- LinkedList 使用 双向链表 实现存储,按序号索引数据需要进行向前或向后遍历,但是插入数据时只需要记录本项的前后项即可,所以插入删除速度较快!
-
vector是线程(Thread)同步(Synchronized)的,所以它也是线程安全的,(即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性,但实现同步需要很高的花费,因此,访问它比访问ArrayList慢,性能不如ArrayList)
-
而Arraylist是线程异步(ASynchronized)的,是不安全的。如果不考虑到线程的安全因素,一般用Arraylist效率比较高。
-
如果集合中的元素的数目大于目前集合数组的长度时,vector增长率为目前数组长度的100%,而arraylist 增长率为目前数组长度的50%. 如果在集合中使用数据量比较大的数据,用vector有一定的优势。
11. 数组Array 和 集合ArrayList 有何区别?
-
Array可以容纳基本类型和对象;
而ArrayList只能容纳对象(当向集合插入不同类型的数据后,ArrayList 都会将数据当作object存储,在进行数据处理时容易出现类型不匹配的错误,使用时需要进行类型转换处理,存在装箱与拆箱操作,造成性能大量损耗的现象。) -
Array 需要在声明时指定大小;
而 ArrayList 大小是动态扩充与收缩的,在声明ArrayList对象时不需要指定它的长度。
12. 在 Queue 中 poll()和 remove()有什么区别?
poll() 和 remove() 都是移除队首元素
- poll() 移除并获取队首元素,若成功,则返回队首元素;否则返回null;
- remove() 移除队首元素,若移除成功,则返回true;如果移除失败(队列为空),则会抛出异常;
13. 哪些集合类是线程安全的?
线程安全: 即某一时刻只有一个线程能够写Vector,避免多线程同时写而引起的不一致性
-
Vector
:就比 Arraylist 多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。 -
Statck
:堆栈类,先进后出,继承于Vector。 -
HashTable
:就比 Hashmap 多了个线程安全。 -
Enumeration
:枚举,相当于迭代器 iterator。
- 👉 Java Enumeration接口
- 迭代器
iterator
👇
public class Test{
public static void main(String[] args) {
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("HAHAHAHA");
// 使用迭代器进行相关遍历
Iterator<String> ite=list.iterator();
while(ite.hasNext()) {
System.out.println(ite.next());
}
}
}
14. 迭代器 Iterator 是什么?
-
在Java中,有很多的数据容器,对于这些的操作有很多的共性。Java采用了迭代器来为各种容器提供了公共的操作接口。这样使得对容器的遍历操作与其具体的底层实现相隔离,达到解耦的效果。
-
迭代器(也是一种设计模式),通常被称为轻量级对象,因为创建它的代价小。
-
它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构。
15. Iterator 怎么使用?有什么特点?
Java中的Iterator功能比较简单,并且只能单向移动:
-
第一次调用Iterator的next()方法时,它返回序列的第一个元素。
注意:iterator()方法是java.lang.Iterable接口,被Collection继承。 -
使用
next()
获得序列中的下一个元素。 -
使用
hasNext()
检查序列中是否还有元素。 -
使用
remove()
将迭代器新返回的元素删除。
Iterator是Java迭代器最简单的实现,为List设计的 ListIterator
具有更多的功能,它可以从两个方向遍历List,也可以从List中插入和删除元素。
ListIterator
👇
下面使用 ListIterator 来对 list 进行 边遍历边添加元素 操作:
16. Iterator 和 ListIterator 有什么区别?
-
Iterator可用来遍历Set和List集合,但是ListIterator只能用来遍历List。
-
Iterator对集合只能是前向遍历,ListIterator既可以前向也可以后向。
-
ListIterator实现了Iterator接口,并包含其他的功能,比如:增加元素,替换元素,获取前一个和后一个元素的索引,等等。