文章目录
- Java集合
-
- [1.2 流程图关系](#1.2 流程图关系)
- [1.3 底层实现](#1.3 底层实现)
- [1.4 集合与数组的区别](#1.4 集合与数组的区别)
-
- [1.4.1 元素类型](#1.4.1 元素类型)
- [1.4.2 元素个数](#1.4.2 元素个数)
- [1.5 集合的好处](#1.5 集合的好处)
- [1.6 List集合我们以ArrayList集合为例](#1.6 List集合我们以ArrayList集合为例)
- [1.7 迭代器的常用方法](#1.7 迭代器的常用方法)
- [1.8 ArrayList、LinkedList和Vector的区别](#1.8 ArrayList、LinkedList和Vector的区别)
-
- [1.8.1 说出ArrayList,Vector, LinkedList的存储性能和特性](#1.8.1 说出ArrayList,Vector, LinkedList的存储性能和特性)
- [1.8.2 多线程场景下如何使用 ArrayList?](#1.8.2 多线程场景下如何使用 ArrayList?)
- [1.8.3 为什么 ArrayList 的 elementData 加上 transient 修饰?](#1.8.3 为什么 ArrayList 的 elementData 加上 transient 修饰?)
- [1.9 Set集合的特点:](#1.9 Set集合的特点:)
-
- [1.9.1 说一下 HashSet 的实现原理?](#1.9.1 说一下 HashSet 的实现原理?)
- [1.9.2 HashSet如何检查重复?HashSet是如何保证数据不可重复的?](#1.9.2 HashSet如何检查重复?HashSet是如何保证数据不可重复的?)
- [1.10 TreeSet对元素进行排序的方式:](#1.10 TreeSet对元素进行排序的方式:)
- [1.11 List,Set,Map集合的特点 & 区别](#1.11 List,Set,Map集合的特点 & 区别)
- [1.12 HashMap和Hashtable的区别](#1.12 HashMap和Hashtable的区别)
- [1.3 HashSet 与 HashMap的区别](#1.3 HashSet 与 HashMap的区别)
Java集合
1.2 流程图关系
1.3 底层实现
ArrayList:底层是数组 ,默认长度为0,调用add以后看情况,不指定长度默认长度为10
ArrayList的扩容机制_arraylist扩容-CSDN博客
LinkedList:底层是链表
Vector:底层是数组
HashSet:底层是哈希表
TreeSet:红黑树
HashMap:数组+链表
Hashtable:数组+链表
LinkedHashMap:数组+链表+红黑树
1.4 集合与数组的区别
1.4.1 元素类型
集合:引用类型(存储基本类型是自动装箱)
数组:基本类型、引用类型
1.4.2 元素个数
集合:不固定、可任意扩展
数组:固定,不能改变容量
1.5 集合的好处
不受容器大小限制,可以随时添加、删除元素,提供了大量操作元素的方法(判断、获取等)
List集合
List集合的特点:
可重复性(可以添加相同的元素)、有序(存取顺序相同)
List的主要方法有:
add、get、remove、set、iterator、contains、addAll、removeAll、indexOf、toArray、clear、isEmpty
1.6 List集合我们以ArrayList集合为例
ArrayList集合
java.util.ArrayList是大小可变的数组的实现,存储在内的数据称为元素。此类提供一些方法来操作内部存储的元素。ArrayList中可以不断添加元素,其大小也自动增长。
java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList集合是最常用的集合。
泛型:即泛指任意类型,幼教参数化类型,对具体类型的使用起到辅助作用,类似于方法的参数
1.7 迭代器的常用方法
next():返回迭代的下一个元素
hasNext():如果仍有元素可以迭代,则返回true
注意:列表迭代器是List 体系独有的遍历方式,可以在对集合遍历的同时进行添加、删除等操作
但是必须通过调用列表迭代器的方法来实现
1.8 ArrayList、LinkedList和Vector的区别
-
线程同步,Vector线程安全,ArrayList线程不安全,因为Vector的实现有synchronized锁
-
效率问题,Vector效率低,ArrayList效率高
-
增长数量,Vector以2倍增长,ArrayList以1.5倍增长
1.8.1 说出ArrayList,Vector, LinkedList的存储性能和特性
(1) ArrayList和Vector使用数组存储元素;LinkedList使用链表存储元素
(2) ArrayList和Vector插入删除数据时,需要搬运数据,效率较差;LinkedList使用链表,不需要搬运数据,效率高。
(3) ArrayList和Vectory查询时,按数组下标查询,不需要遍历,效率高;LinkedList需要遍历,查询效率底。
1.8.2 多线程场景下如何使用 ArrayList?
ArrayList 不是线程安全的,如果遇到多线程场景,可以通过 Collections 的 synchronizedList 方法将其转换成线程安全的容器后再使用。例如像下面这样:
java
List<String> synchronizedList = Collections.synchronizedList(list);
synchronizedList.add("aaa");
synchronizedList.add("bbb");
for (int i = 0; i < synchronizedList.size(); i++) {
System.out.println(synchronizedList.get(i));
}
1.8.3 为什么 ArrayList 的 elementData 加上 transient 修饰?
ArrayList 中的数组定义如下:
java
private transient Object[] elementData;
java
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
可以看到 ArrayList 实现了 Serializable 接口,这意味着 ArrayList 支持序列化。transient 的作用是说不希望 elementData 数组被序列化,重写了 writeObject 实现:
java
private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException{
*// Write out element count, and any hidden stuff*
int expectedModCount = modCount;
s.defaultWriteObject();
*// Write out array length*
s.writeInt(elementData.length);
*// Write out all elements in the proper order.*
for (int i=0; i<size; i++)
s.writeObject(elementData[i]);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
每次序列化时,先调用 defaultWriteObject () 方法序列化 ArrayList 中的非 transient 元素,然后遍历 elementData,只序列化已存入的元素,这样既加快了序列化的速度,又减小了序列化之后的文件大小。
1.9 Set集合的特点:
不可重复(元素具有唯一性)、无序(元素的存取顺序是不固定的)
Set的主要方法有:
add、remove、iterator、contains、addAll、removeAll、toArray、clear、isEmpty
HashSet:内部的数据结构是哈希表,是线程不安全的。
HashSet中保证集合中元素是唯一的方法:通过对象的hashCode和equals方法来完成对象唯一性的判断。
如果对象的hashCode值不同,则不用判断equals方法,就直接存到HashSet中。
如果对象的hashCode值相同,需要用equals方法进行比较,如果结果为true,则视为相同元素,不存,如果结果为false,视为不同元素,进行存储。
注意:如果元素要存储到HashCode中,必须覆盖hashCode方法和equals方法。
TreeSet:可以对Set集合中的元素进行排序,是线程不安全的。
**TreeSet:**中判断元素唯一性的方法是:根据比较方法的返回结果是否为0,如果是0,则是相同元素,不存,如果不是0,则是不同元素,存储。
1.9.1 说一下 HashSet 的实现原理?
HashSet 是基于 HashMap 实现的,HashSet 的值存放于HashMap 的key 上,HashMap 的value 统一为PRESENT ,因此 HashSet 的实现比较简单,相关 HashSet 的操作,基本上都是直接调用底层 HashMap 的相关方法来完成,HashSet 不允许重复的值。
1.9.2 HashSet如何检查重复?HashSet是如何保证数据不可重复的?
向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash 值,同时还要结合equles 方法比较。
HashSet 中的add ()方法会使用HashMap 的put()方法。
HashMap 的 key 是唯一的,由源码可以看出 HashSet 添加进去的值就是作为HashMap 的key,并且在HashMap 中如果K/V相同时,会用新的V覆盖掉旧的V,然后返回旧的V。所以不会重复( HashMap 比较key是否相等是先比较hashcode 再比较equals )。
以下是HashSet 部分源码:
java
private static final Object PRESENT = new Object();
private transient HashMap<E,Object> map;
public HashSet() {
map = new HashMap<>();
}
public boolean add(E e) {
// 调用HashMap的put方法,PRESENT是一个至始至终都相同的虚值
return map.put(e, PRESENT)==null;
}
1.10 TreeSet对元素进行排序的方式:
元素自身具备比较功能,即自然排序,需要实现Comparable 接口,并覆盖其compareTo方法。
元素自身不具备比较功能,则需要实现Comparator 接口,并覆盖其compare方法。
注意:LinkedHashSet 是一种有序的Set集合,即其元素的存入和输出的顺序是相同的。
1.11 List,Set,Map集合的特点 & 区别
List、Set、Map 是否继承自 Collection 接口?List、Map、Set 三个接口存取元素时,各有什么特点?
Java 容器分为 Collection 和 Map 两大类,Collection 集合的子接口有Set、List、Queue 三种子接口。我们比较常用的是Set、List,Map 接口不是collection的子接口。
Collection 集合主要有List 和Set两大接口
List :一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null 元素,元素都有索引 。常用的实现类有 ArrayList、LinkedList 和 Vector 。
Set :一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素 ,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet 。
Map 是一个键值对集合,存储键、值和之间的映射。 Key 无序,唯一;value 不要求有序,允许重复。Map 没有继承于Collection 接口,从Map集合中检索元素时,只要给出键KEY对象,就会返回对应的值对象。
Map 的常用实现类:HashMap、TreeMap、HashTable、LinkedHashMap、ConcurrentHashMap
关系图如下:
1.12 HashMap和Hashtable的区别
-
线程同步,Hashtable线程安全,HashMap线程不安全
-
效率问题,Hashtable效率低,HashMap效率高
-
HashMap 可以使用null 作为key ,Hashtable 不可以使用null为key
-
HashMap 使用的是新实现,继承AbstractMap ,而Hashtable 是继承Dictionary类,实现比较老
-
Hash 算法不同,HashMap 的hash 算法比Hashtable 的hash算法效率高
-
HashMap 把Hashtable 的contains 方法去掉了,改成containsValue 和containsKey 。因为contains方法容易让人引起误解。
-
取值不同,HashMap 用的是Iterator 接口,而Hashtable 中还有使用Enumeration接口