数组也是一种容器,可以存放对象或基本数据类型,数组的劣势在于不灵活,容器需要事先定义好,不能随着需求而改变而扩容。而容器则可以随时扩容来装对象,容器也称为集合。
将数据一个一个的进行存储
基于 key 和 value 的结构存储数据
是 List 接口的容器实现类,是 List 具体实现,ArrayList 底层用数组实现存储。1.8之前 ArrayList在 new 的时候就会创建默认长度为 10 的数组,而 1.8 则在 new 的时候会创建空数组,在添加的时候才进行长度创建,扩容是以 1.5 倍扩容。
特点:查询效率高,增删改查效率低,线程不安全(可以并行的调用)
使用和 ArrayList 相同,都实现 List 接口。底层是数组实现的,相关方法都加了同步检查,因此线程安全,效率低Vector 是立即初始化,容器扩容是 2 倍扩容。
底层使用的是双向链表实现的存储。特点是:查询效率低,增删效率高,线程不安全。双向链表也叫双链表,是链表的一种,它的每个数据节点中都有两个指针,分别指向前 一个节点和后一个节点。 所以,从双向链表中的任意一个节点开始,都可以很方便地找到 所有节点。
ArrayList 底层是数组,查询效率高(通过索引获取元素),增删改效率低(增删的时候要做索引的移动,数组个数越多,移位个数也越多)
LikedList 底层是双向链表,查询效率低(查询时,节点越多需要查找该数据的节点就越多,因此节点越多查询的就越慢),增删效率高(增删不涉及元素移动,而是直接将元素放在节点上,进行双向链接即可)
没有元素索引,只能遍历查找,不允许加入重复元素
Set 特点:无序、不可重复。无序指 Set 中的元素没有索引,我们只能遍历查找;不可 重复指不允许加入重复的元素。更确切地讲,新元素如果和 Set 中某个元素通过 equals() 方法对比为 true,则只能保留一个。
Set 常用的实现类有:HashSet、TreeSet 等,我们一般使用 HashSet。
HashSet 是一个没有重复元素的集合,不保证元素的顺序。而且 HashSet 允许有 null 元 素。HashSet 是采用哈希算法实现,底层实际是用 HashMap 实现的(HashSet本质就是一个简化版的 HashMap),因此,查询效率和增删效率都比较高。
HashSet 是一个不保证元素顺序,切不重复的集合,线程不安全,HashSet 允许有 null 元素(默认长度 16,下标 0-15)
由于在 1.7还未引入链表转红黑树因此 1.8 引入当数组大于 64 时,节点个数大于 8 会转换为红黑树,转载其他作者博文进行参考
1.7 HashMap 源码分析
1.8 HashMap源码分析
TreeSet 是一个可以对元素进行排序的容器。底层实际是用 TreeMap 实现的,内部维持了一个简化版的 TreeMap,通过 key 来存储 Set 的元素。 TreeSet 内部需要对存储的元 素进行排序,因此,我们需要给定排序规则。
在元素自身实现比较规则时,需要实现 Comparable 接口中的 compareTo 方法,该方法中用来定义比较规则。TreeSet 通过调用该方法来完成对元素的排序处理。
通过比较器定义比较规则时,我们需要单独创建一个比较器,比较器需要实现 Comparator 接口中的 compare 方法来定义比较规则。在实例化 TreeSet 时将比较器对象交给 TreeSet 来完成元素的排序处理。此时元素自身就不需要实现比较规则了。
产生 1-10 之间的随机数([1,10]闭区间),将不重复的 10 个随机数放到容器中。
package com.container;
import java.util.ArrayList;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
while (true) {
int num = (int) (Math.random() * 10) + 1;//Math.random()返回 [0-1)之间的随机数
//判断当前元素在容器中是否存在
if (!list.contains(num)) {//不包含 num 元素就进行添加
list.add(num);
}
//结束循环
if (list.size() == 10) {
break;
}
}
for (Integer i : list) {
System.out.println(i);
}
}
}
package com.container;
import java.util.HashSet;
import java.util.Set;
public class SetDemo {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
while (true) {
int num = (int) (Math.random() * 10) + 1;
//将元素添加容器中,由于 set 类型容器是不允许重复元素,所以不需要进行判断
set.add(num);
if (set.size() == 10) {
break;
}
}
//hashCode在 Integer 方法时,返回的就是数值本身,因此看似排序了,实际只是凑巧
for (Integer i : set) {
System.out.println(i);
}
}
}
Map 接口定义了双例集合的存储特征,它并不是 Collection 接口的子接口。双例集合的存储特 征是以 key 与 value 结构为单位进行存储。
HashMap 是 Map 接口的接口实现类,它采用哈希算法实现,是 Map 接口最常用的 实现类。 由于底层采用了哈希表存储数据,所以要求键不能重复,如果发生重复,新的值 会替换旧的值。 HashMap 在查找、删除、修改方面都有非常高的效率。
HashMap 底层实现采用了哈希表,这是一种非常重要的数据结构。
数据结构中由数组和链表来实现对数据的存储,他们各有特点。
(1) 数组:占用空间连续。寻址容易,查询速度快。但是,增加和删除效率非常低。
(2) 链表:占用空间不连续。寻址困难,查询速度慢。但是,增加和删除效率非常高。 那么,我们能不能结合数组和链表的优点(即查询快,增删效率也高)呢? 答案就是“哈希表”。 哈希表的本质就是“数组+链表”。需要注意的是
Hash 值决定节点放在什么位置,也就是节点对象在数组当中的索引数
(1) 获得key对象的hashcode
首先调用 key 对象的 hashcode()方法,获得 key 的 hashcode 值。
(2) 根据 hashcode 计算出 hash 值(要求在[0, 数组长度-1]区间)
hashcode 是一个整数,我们需要将它转化成[0, 数组长度-1]的范围。我们要求转化后的 hash 值尽量均匀地分布在[0,数组长度-1]这个区间,减少“hash 冲突”
TreeMap 和 HashMap 同样实现了 Map 接口,所以,对于 API 的用法来说是没有区 别的。HashMap 效率高于 TreeMap;TreeMap 是可以对键进行排序的一种容器,在需要 对键排序时可选用 TreeMap。TreeMap 底层是基于红黑树实现的。
在使用 TreeMap 时需要给定排序规则:
Collection接口继承了Iterable接口,在该接口中包含一个名为iterator的抽象方法,所 有实现了Collection接口的容器类对该方法做了具体实现。iterator方法会返回一个Iterator 接口类型的迭代器对象,在该对象中包含了三个方法用于实现对单例容器的迭代处理。
原理:通过接口定义的方法来判断元素是否存在,若有元素就获取当前游标的方法,并将游标移动到下一位,具体实现方法:
Collections 是一个工具类,它提供了对 Set、List、Map 进行排序、填充、查找元素 的辅助方法。该类中所有的方法都为静态方法。
常用方法:
原文:https://www.cnblogs.com/freebule/p/14462668.html