java集合(容器)总结
前言
-
学习java的集合首先我们要了解一些基本的数据结构以及他们的特点。我们常见的数据结构有数组、链表、栈、队列。各自有各自的特点。
-
数组(Arrays)
定义:简单的来说就是一系列相同类的数据集合。数组在定义之初我们要指定他的长度以及该数组所要存放的数据类型。数组的使用都逃不过三步:
声明->分配空间->赋值,当然赋值可以省略。
数据类型[] 数组名称 = new 数据类型[长度];
数据类型 数组名称[] = new 数据类型[长度];
以上两种都差不多看个人习惯
数据类型[] 数组名称 = null;
-
简单数组的特点:元素是顺序由下标决定,数组的下标从0开始计数。索引其下标是有序的,而元素的顺序就是有你存储的顺序决定,他的元素存储区域都是连续的。数组的输出方法用toString()方法。
-
链表基本概念
链表存储元素空间分成两个部分数据域以及指针域,它存储数据的空间可以是不连续的。 -
数组与链表的区别
数组查找快,增删慢。而链表是增删快,查找慢。
数组查找元素只要知道存储数据的下标就可以直接找到。数组的删除一个元素其其他元素的位置也会随之改变。
链表查找元素总是需要检索所有元素效率慢,而删除元素则只需断开指针从新指向即可。
相信大家都有一个疑惑:增加删除元素不是先要找到元素位置再进行增加删除吗?为什么还是选用链表呢? -
数组增加删除元素:他会将数组先扩大再将原有的元素放入其中。这就会极大的影响效率以及内存。
-
链表增加删除元素:他直接将指针从新指向新的地址即可。
集合的分类
java中常用集合有list、set、map三种集合。
1、 list集合(ArrayList、LinkedList、Vector、Stack)
1、1 ArrayList集合(数组)
ArrayList是接口Collection实现类,里面有常用的增删改查方法当他在添加元素时,容量大于10,数组的容量会自动扩充。数组都是建新数组再将旧数组移进新数组。
1、2 linkedList集合
这是一个底层是链表集合,具有链表的特点。元素存储不是连续的空间,其添加删除快速。
- LinkedList和ArryList的区别
最明显的区别是 ArrrayList底层的数据结构是数组,支持随机访问,而 LinkedList 的底层数据结构是双向循环链表,不支持随机访问。使用下标访问一个元素,ArrayList 的时间复杂度是 O(1),而 LinkedList 是 O(n)。
1、3 Vector
- 和ArryList集合相似,常用操作几乎相同。区别在于Vector是同步的,ArryList是线程安全的动态数组。而ArrayList更加通用,因为我们可以使用Collections工具类轻易地获取同步列表和只读列表。
1、4 Stack
- Stack继承自Vector,实现一个后进先出的堆栈。Stack提供5个额外的方法使得Vector得以被当作堆栈使用。push、pop、peek、empty、search 方法。
1、5 list集合总结
ArrayList、LinkedList、Vector
- ArrayList
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程不安全,效率高 - LinkedList
优点: 底层数据结构是链表,查询慢,增删快。
缺点: 线程不安全,效率高 - Vector
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程安全,效率低
2、set集合(hashSet、LinkHashSet、TreeSet)
2、1 hashSet集合
-
hashSet底层是哈希表,其结构决定了它存储的元素是不允许重复的。这里就要引入一个知识**散列函数**有以下几个特点:
-
确定性
如果两个散列值是不相同的(根据同一函数),那么这两个散列值的原始输入也是不相同的 -
散列碰撞
散列函数的输入和输出不是唯一对应关系的,如果两个散列值相同,两个输入值很可能是相同的,但也可能不同。简单来说就是前面可推后面,后面不一定可以推前面 -
不可逆性
一个哈希值对应无数个明文,理论上你并不知道哪个是,对这个有点糊涂。 -
HashSet元素无序且唯一,线程不安全,效率高,可以存储null元素,元素的唯一性是靠所存储元素类型是否重写hashCode()和equals()方法来保证的,如果没有重写这两个方法,则无法保证元素的唯一性。 HashSet添加元素先经过hashCode()方法生成哈希值,然后通过equals()方法比较是否相同,相同不添加。
2、2 LinkedHashSet集合
- 由它名字就可以猜想它的底层就是有序链表+哈希表实现的。哈希表保证元素是不重复的,链表保证元素是有序的。
2、3 TreeSet集合
- 它的底层是红黑树。它的元素也是唯一有序的,重写hashCode()和equals()方法来保证元素的唯一性。建议先学习红黑树。TreeSet有两种存储数据的方法自然排序和制定排序。
2、4 Set集合总结
- Set集合没一个是线程安全的。
- HashSet是基于Hash算法实现的,其性能通常都优于TreeSet。适合快速查找的Set,我们通常都应该使用HashSet,在我们需要排序的功能时,我们才使用TreeSet。
3、Map集合(HashMap、LinkedHashMap、TreeMap、ConcurrentHashMap、HashTable)
- Map集合是key+value的形式存储数据的。
3、1 HashMap集合
- 它底层是数组+链表,数组上面有hashcode()方法,链表来存储数据。它是基于Hash算法实现的,传入key值,再根据hashcode()计算哈希值,然后根据hash值获取value。当我们计算的hash值相同时称为hash冲突,当链表存储的数据大于8个时,它会由链表结构转换为红黑树的结构。
3、2 LinkedHashMap集合
- 看名字我们就知道它是链表+HashMap实现的,那就错了他这个链表是有序双向链表。这样就可以维持HashMap元素有序。
3、3 TreeMap集合
- TreeMap底层是红黑树结构,每个key-value对作为红黑树的一个节点。和TreeSet相似也有两种存储数据的方法自然排序和制定排序。
3、4 ConcurrentHashMap集合
- 这是JDK1.5之后Java.util.concurrent并发包下的一个线程安全类,它是HashMap的安全类。JDK1.7的 ConcurrentHashMap 底层采用 分段的数组+链表 实现,JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树。
3、5 HashTable集合
- Hashtable和前面介绍的HashMap很类似,它也是一个散列表,存储的内容是键值对映射,Hashtable中的函数都是同步的,这意味着它也是线程安全的,Hashtable中key和value都不可以为null。
Map集合总结
- Map以key和value的形式存储数据,它们都可以使任何引用类型的数据,但key不能重复。所以通过指定的key就可以取出对应的value。
- TreeMap是有序的,HashMap和HashTable是无序的。
- Hashtable的方法是同步的,HashMap的方法不是同步的。这是两者最主要的区别。
4、集合的选择
5、常见的面试题
5、1 List,Set,Map三者的区别?
- List(考虑数据是否有序): List接口存储的元素是不唯一有序的元素
- Set(考虑的是唯一的性质): 不允许重复的元素。
- Map(考虑的是键值对的方式): 使用键值对存储。Map会维护与Key有关联的值。
5、2 ArrayList与Array的区别?
- Array可以存储对象以及对象,而ArrayList只能存储对象
- Array是固定大小的,而ArrayList大小可以自动扩充
- 他们两个的内置方法不同,Array没有ArrayList多,比如:addAll、removeAll等。
5、3 ArrayList 与 Vector 区别?
- 线程安全性:Vector时使用Synchroninzed来实现线程安全,ArrayList是非线程安全的。
- 性能:ArrayList性能优于Vector
- 扩容机制:Vector扩容是每次扩容为原来的一倍,而ArrayList是扩容为原来的0.5倍。
5、4 怎么确保一个集合不能被修改?
- 可以使用 Collections. unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都会抛出 Java. lang. UnsupportedOperationException 异常。
List<String> list = new ArrayList<>();
list. add("x");
Collection<String> clist = Collections. unmodifiableCollection(list);
clist. add("B"); // 运行时此行报错
System. out. println(list.size());
5、5 HashMap 和 Hashtable 的区别?
- 存储:HashMap允许key和value为null,而Hashtable不能为空。
- 线程安全:Hashtable是线程安全的,HashMap是非线程安全的。
- Hashtable是保留类现在不建议使用,在单线程的时候建议使用HashMap,在多线程的时候我们可以使用HashMap的安全类ConcurrentHashMap。
5、6 迭代器Iterator是什么?怎么使用?有什么特点?
- Iterator迭代器可以遍历任何集合,迭代器取代了Java集合中Enumeration,它允许调用者在迭代过程中移除元素。
- 迭代器的使用
List list = new ArrayList();
Iterator it = list.iterator();//获取迭代器
while(it.hasNext()){
String obj = it.next();
System.out.println(obj);
}
- 迭代器的特点:使用迭代器可以保证更加安全,确保遍历元素之前没有被修改,改了会抛出ConcurrentModificationException异常。
5、7 Iterator和Listiterator有什么区别?
- Iterator可以遍历Set和List集合,而Listiterator只能遍历List集合。
- Iterator只能单向遍历,Listiterator可以双向遍历(前/后)
- Listiterator相比Iteratorr多了一些方法,比如添加一个元素、替换一个元素、获取前一个或者后一个元素的索引位置。