Java容器分为Collection和Map两大类,其下又有很多子类
一:Iterable 接口
1:Iterable 是一个超级接口 被collection所继承,它只有一个方法:Iterator<T> iterator(); //返回一个迭代器。
2:迭代器是一种设计模式,它是一个对象,它可以遍历并选择序列中的对象。迭代器被称为‘轻量级’对象,因为创建代价小。
3:Java中的Iterator功能比较简单,并且只能单向移动:
(1) 使用方法iterator()要求容器返回一个Iterator。第一次调用Iterator的next()方法时,它返回序列的第一个元素。注意:iterator()方法是java.lang.Iterable接口,被Collection继承。
(2) 使用next()获得序列中的下一个元素。
(3) 使用hasNext()检查序列中是否还有元素。
(4) 使用remove()将迭代器新返回的元素删除。
4:Iterator是Java迭代器最简单的实现。像遍历集合就是迭代器的使用。
二:Collection接口
1:List 接口
1):List 是有序的,用户可以根据元素的索引访问元素。
2):List 可以插入重复的值。
3):List 接口提供了特殊的迭代器——ListIterator,除了允许Iterator接口提供正常操作外,该迭代器还允许元素插入和替换,以及双向访问。
4):List 的子类—— List 的实现类,有:ArrayList、LinkedList、Vector,
4-1):ArrayList
1:是基于数组实现的List 类,它封装了一个动态的、增长的、允许再分配的Object[] 数组,它允许对元素快速的随机访问。(线程不安全)
2:当从ArrayList中间位置插入或删除元素时,需要对数组复制、移动、代价比较高,因为它适合随机查找和遍历,不适合插入和删除。
4-2):LinkedList
1:是用双向链表结构存储数据的(线性的存储方式),很适合动态数据的添加和删除。随机访问和遍历速度比较慢。
2:它还实现Deque接口,专门用于操作表头和表尾元素,可以当作堆栈、队列和双向队列使用。
4-3):Vector
1:也是通过数组实现,它支持线程的同步,线程安全,即某一个时刻只能有一个线程能够写Vector,避免多线程同时写入而引起的不一致性。
但实现同步需要花费很高的代价, 因此,访问它比访问ArrayList慢。所以,现在已不常用。
2:Stack 类,Stock 是Vector 提供的一个子类,用于模拟 “栈” 这种数据结构(LIFO后进先出)
List 接口的排序可以通过Collections.sort() 来排序。只需要继承Compareble接口后,重写 compareTo() 方法
2:Set 接口
1):Set 要满足无序性、确定性、单一性,所以Set 是无序、不可重复的,Set 只有有一个null。
2):Set 判断两个对象相同不是使用 == 运算符,而是用 equals方法,
3):Set 的子类—— Set的实现类,有:HashSet、TreeSet、LinkedHashSet(从HashSet继承而来)。
3-1):HashSet 使用HASH算法来存储集合中的元素,因此具有良好存储和查找性能。当往HashSet 存值时,HashSet会调用该对象的 hashCode() 方法得到该对象 hashCode 值,
然后根据 hashCode 值决定该对象存放在 HashSet 中的存储位置。HashSet 是用equals来判断两个元素是否相等的,并且两个对象的hashCode() 方法的返回值相等。
HashSet 的实现原理:HashSet是基于HashMap实现的,HashSet 底层使用HashMap来保存元素的,HashSet不允许有重复的值。
3-1-1):LinkedHashSet(类) 集合也是根据hashCode值来决定存放的位置,和HashSet不同的是,它同时使用链表维护元素的次序,
3-2):StoredSet 接口,此接口主要用于排序,实现此接口的子类都属于排序的子类。 TreeSet 是StoredSet的实现类,TreeSet 可以确保集合元素处于排序状态 。
3-3):EnumSet 是一个专门为枚举设计的类,EnumSet中的所有元素必须是指定枚举类型的枚举值,
3:Queue
1):Queue 用于模拟 “队列” 数据结构(FIFO),新插入的元素放入队尾,对头存在保存时间最长的元素。
2):PriorityQueue 类 ——优先队列,它不是按照插入顺序来存放元素的,而是按照队列中某个属性的大小来排列的,故而叫优先队列。
3):Deque 接口 —— 双端对列,
3-1):ArrayDeque(类),基于数组的双端队列,类似于ArrayList有一个Object[] 数组。
3-2):LinkedList (类),参考上文介绍。
简单回顾一下上述三个接口的区别
容器名 | 是否有序 | 是否可重复 | null的个数 |
---|---|---|---|
List | 有序 | 可重复 | 允许多个null |
Set | 无序 | 不可重复 | 只允许一个null |
Queue | 有序(FIFO) | 可重复 | 通常不允许插入null |
三:Map接口,Map的子类、子接口
Map是一个接口。Map用于保存具有映射关系的数据,每个Entry都有key-value两个对象,value可以重复,key不可重复。Map可以有多个value为null,只能有一个key为null。
1:HashMap (类)
1):HashMap 和HashSet一样不能保证元素的顺序 HashMap也不能保证key-value的顺序。HashMap 也是通过equals() 方法比较
2):LinkedHashMap(类),使用双向链表结构来维护key-value对的次序。
3):非线程安全
4):实现原理——基于hash算法实现,当传入key时,HashMap会根据key.hashCode() 计算出key的hash值,然后把值保存到bucket里,当计算出的hash值相同时,我们称之为
hash冲突,HashMap的做法是用链表和红黑树存储相同的hash值的value。当hash 冲突比较少时,使用链表,否则使用红黑树。
5):数据结构是:数据+链表+红黑树
2:HashTable (类)
1):是一个古老的Map实现类
2):Properties(类)对象在处理属性文件特别方便(windows平台的.ini文件)。Properties类可以把Map对象和属性文件关联,从而把Map的key-value对写入到属性文件中,
也可以把属性文件中的“属性名-属性值”加载进Map对象中。
3):线程安全
3:SortedMap(接口),实现接口类是TreeMap
1):如同Set->SortedSet->TreeSet一样,Map也有Map->SortedMap->TreeMap的继承关系。
2):TreeMap(类) 是一个红黑树结构,每个键值对都作为一个红黑树的节点。TreeMap存储键值对时,需要根据key对节点进行排序,TreeMap可以保证所有的key-value对
处于有序状态。同时,TreeMap 有两种排序方式:自然排序、定制排序。
4:WeakHashMap
5: IdentityHashMap(类)
6:EnumMap(类)
常见问题:
1:ArrayList 和 LinkedList 的区别是什么?
1):数据结构实现:ArrayList 是动态数组的数据结构实现,而 LinkedList 是双向链表的数据结构实现。
2):随机访问效率:ArrayList 比 LinkedList 在随机访问的时候效率要高,因为 LinkedList 是线性的数据存储方式,所以需要移动指针从前往后依次查找。
3):增加和删除效率:在非首尾的增加和删除操作,LinkedList 要比 ArrayList 效率要高,因为 ArrayList增删操作要影响数组内的其他数据的下标。
4):综合来说,在需要频繁读取集合中的元素时,更推荐使用 ArrayList,而在插入和删除操作较多时,更推荐使用 LinkedList。
2:如何实现数组和 List 之间的转换?
1):数组转 List:使用 Arrays. asList(array) 进行转换。
2):List 转数组:使用 List 自带的 toArray() 方法。
3:ArrayList 和 Vector 的区别是什么?
1):线程安全:Vector 使用了 Synchronized 来实现线程同步,是线程安全的,而 ArrayList 是非线程安全的。
2):性能:ArrayList 在性能方面要优于 Vector。
3):扩容:ArrayList 和 Vector 都会根据实际的需要动态的调整容量,只不过在 Vector 扩容每次会增加 1倍,而 ArrayList 只会增加 50%
4:Array 和 ArrayList 有何区别?
1):Array 可以存储基本数据类型和对象,ArrayList 只能存储对象。
2):Array 是指定固定大小的,而 ArrayList 大小是自动扩展的。
3):Array 内置方法没有 ArrayList 多,比如 addAll、removeAll、iteration 等方法只有 ArrayList 有。
5:在 Queue 中 poll()和 remove()有什么区别?
1):相同点:都是返回第一个元素,并在队列中删除返回的对象。
2):不同点:如果没有元素 poll()会返回 null,而 remove()会直接抛出 NoSuchElementException 异常。
代码示例:
Queue queue = new LinkedList();
queue. offer(“string”); // add
System. out. println(queue. poll());
System. out. println(queue. remove());
System. out. println(queue. size());
6:哪些集合类是线程安全的?
Vector、Hashtable、Stack 都是线程安全的,而像 HashMap 则是非线程安全的,不过在 JDK 1.5 之后随着 Java. util. concurrent 并发包的出现,它们也有了自己对应的线程安全类,比如 HashMap 对应的线程安全类就是 ConcurrentHashMap。
7:Iterator 和 ListIterator 有什么区别?
1):Iterator 可以遍历 Set 和 List 集合,而 ListIterator 只能遍历 List。
2):Iterator 只能单向遍历,而 ListIterator 可以双向遍历(向前/后遍历)。
3):ListIterator 从 Iterator 接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。
8:怎么确保一个集合不能被修改?
1):可以使用 Collections.unmodifiableCollection(Collection c) 方法来创建一个只读集合,这样改变集合的任何操作都是抛出Java.lang.UnsupportedOperationException 异常。
2):示例代码如下:
List list = new ArrayList<>();
list. add(“x”);
Collection clist = Collections. unmodifiableCollection(list); //把集合变成只读集合
clist. add(“y”); // 运行时此行报错
System. out. println(list. size());
9:Arrays.sort 和 Collections.sort 实现原理 和区别
1:collection 和 collections 的区别:
1.1:java.util.Collection 是一个集合接口。它提供了对集合对象进行基本操作的通用接口方法。
1.2:java.util.Collections 是针对集合类的一个帮助类,他提供一系列静态方法实现对各种集合的搜索、排序、线程安全等操作。 然后还有混排(Shuffling)、反转(Reverse)、替换所有的元素(fill)、拷贝(copy)、返回Collections中最小元素(min)、返回Collections中最大元素(max)、返回指定源列表中最后一次出现指定目标列表的起始位置( lastIndexOfSubList )、返回指定源列表中第一次出现指定目标列表的起始位置( IndexOfSubList )、根据指定的距离循环移动指定列表中的元素(Rotate);
1.3:事实上Collections.sort方法底层就是调用的array.sort方法。
Collection