文章目录
Iterator接口常用方法
- boolean hasNext()
- E next()
- default void remove()
删除集合里上一次next方法返回的元素 - default void forEachRemaining(Consumer<? super E> action)
- 调用forEachRemaining遍历集合元素时,程序会依次将集合元素传给Consumer的accept方法。
- Consumer action为函数式接口,可以用Lambda表达式实现。
- 通过迭代器调用
Iterable接口常用方法
- Iterator iterator()
返回迭代器对象 - default void forEach(Consumer<? super T> action)
- 调用forEach遍历集合元素时,程序会依次将集合元素传给Consumer的accept方法。
- Consumer action为函数式接口,可以用Lambda表达式遍历集合元素。
- 通过集合调用
- default Spliterator spliterator()
Collection接口常用方法
-
添加
- boolean add(Object obj):
- boolean addAll(Collection coll):
-
删除
- boolean remove(object obj);//会改变集合的长度
- boolean removeAll(Collection coll);//将两个集合中的相同元素,从调用removeAll的集合中删除
- void clear();
-
判断
- boolean contains(object obj);//
- boolean containsAll(Colllection coll);
- boolean isEmpty();判断集合中是否有元素。
-
获取
- int size():
- Iterator iterator();取出元素的方式:迭代器
Map接口常用方法
-
添加:
-
value put(key,value)
返回前一个和key关联的值,如果没有返回null.
如果添加的key值重复,则对应的新的value会替代旧的value,并返回旧的value的值,如果key是第一次添加,则返回null
-
-
删除:
- void clear() //清空map集合。
- value remove(key) //根据指定的key翻出这个键值对,并返回对应key值
-
判断
- boolean containsKey(key):
- boolean containsValue(value):
- boolean isEmpty();
-
获取
-
value get(key):通过键获取值,如果没有该键返回null。
当然可以通过返回null,来判断是否包含指定键。 -
int size(): 获取键值对的个数。
-
Set keySet():获取map中所有键所在的set集合
-
Set<Map.Entry<K,V>> entrySet()
获取此映射所包含的映射关系的set视图,Entry是Map中的静态接口,可以直接访问Map中的内容
Collection values():返回此映射包含的值的Collection视图
-
集合类
集合类的由来
便于存储数量不定的对象
。实现存储数量不定的方法:通过扩容。
集合类VS数组
内容 | 长度 | |
---|---|---|
集合 | 引用类型 | 可变 |
数组 | 引用类型or基本类型 | 固定 |
- 存储任意数量的对象,而非基本类型。如果存储基本类型,会自动装箱为引用类型。
- 对象一旦被装入,就会向上转型为Object类型,因而从集合中取出时也是Object类型。使用泛型后,会自动进行类型转换。
集合类的继承关系
- 完整版
- 简化版
集合类的分类和比较
Iterable | Collection | List | Vector | 元素不唯一 | 有序 | 同步 | 允许null | 基于数组 |
ArrayList | 不同步 | 基于数组 | ||||||
LinkedList | 基于双向链表 | |||||||
Set | HashSet | 元素唯一 | 无序 | 不同步 | 允许null | 基于hash表 | ||
TreeSet | 有序 | 不同步 | 允许null | 基于红黑树 | ||||
Queue | PriorityQueue | |||||||
ArrayDeque |
Map | Hashtable | 键值唯一 | 无序 | 同步 | 不允许null作为键或值 | 基于hash表 |
HashMap | 无序 | 不同步 | null既可以作为键也可以作为值 | 基于hansh表 | ||
TreeMap | 无序 | 不同步 | 允许null作为键或者值(注意事项见下) | 基于红黑树 |
注意事项:
- 当第二次存入key为null的键值对时,如果集合自身不带比较器,那么需要调用元素自身的compareTo()方法,即key.compareTo()方法,此时必然产生NullPointerException异常。
集合遍历方法
- 使用Iterator的hasNext(),next()
- 使用Iterator的forEachRemaining(Lambda表达式)
- 使用集合的forEach(Lambda表达式)
- 使用foreach语句
- 使用for语句对数组结构的List集合进行遍历
常见问题
hashmap和hashtable的区别
HashMap | 不同步 | 允许null作为键或值 | 用containsvalue和containsKey方法 | 实现Map接口的类 |
---|---|---|---|---|
Hashtable | 同步 | 不允许有null的键和值 | 用contains方法方法 | 继承Dictionary 类且实现Map接口的类 |
Iterator和Iterable的区别
- Iterator接口
- 含义上
Iterator接口和Collection、Map接口一样,也是Java集合框架的成员。Collection、Map主要用于盛装对象,Iterator主要用于遍历(迭代)Collection集合中的对象
,因而也叫作迭代器
。Iterator对象必须依附于Collection对象,即如果又一个Iterator对象,则必然有一个与之关联的Collection对象。 - 迭代状态上
Iterator实例可以存储迭代状态,即可以通过hasnext()检查是否有下一个元素,并可以通过next()获取下一个元素
- 含义上
- Iterable接口
- 含义上
Iterable接口是Collection接口的父类,其代表可以迭代的一系列元素
的简单表示。它包含的 iterator() 函数用于返回迭代器对象,从而实现用Iterator迭代Collection对象。 - 迭代状态上
Iterable每次调用 iterator() 函数都会生成一个新的iterator实例,即返回一个从头开始计数的迭代器,多个迭代器是互不干扰的。
- 含义上
Iterator与fast-fail机制
- 什么是fast-fail(快速失败)机制
在用迭代器遍历一个集合对象时,如果遍历过程中对集合对象的内容进行了修改(增加、删除、修改),则会抛出Concurrent Modification Exception
。java.util包下的集合类都是快速失败的
,不能在多线程下发生并发修改(迭代过程中被修改)。 - fast-fail(快速失败)机制的原理
迭代器在遍历时直接访问集合中的内容,并且在遍历过程中使用一个modCount 变量
。集合在被遍历期间如果内容发生变化(调用add、remove、clear等方法
),就会改变modCount的值
。每当迭代器使用hashNext()/next()遍历下一个元素之前,都会检测modCount变量是否为expectedmodCount值
,是的话就返回遍历;否则抛出异常,终止遍历。
注意:这里异常的抛出条件是检测到 modCount!=expectedmodCount 这个条件。如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount值,则异常不会抛出
。因此,不能依赖于这个异常是否抛出而进行并发操作的编程,这个异常只建议用于检测并发修改的bug。 - 为什么需要fast-fail(快速失败)机制
"快速失败"是java集合的一种错误检测机制,其作用主要是为了防止当多线程对集合进行结构上的改变或者集合在迭代元素时直接调用自身方法改变集合结构而没有通知迭代器时,会造成数据不一致的问题
,即保证操作的隔离性
(我自己的理解)。当然,在单线程操作中也会出现为题,如:ArrayList<String> arrayList=new ArrayList<>(); arrayList.add("hello"); arrayList.add("how are you"); arrayList.add("I'm ok"); Iterator<String> iterator=arrayList.iterator(); boolean shouldDelete=true; while (iterator.hasNext()){ String string=iterator.next(); if(shouldDelete){ shouldDelete=!shouldDelete; arrayList.remove(2); } }
equals() 和 hashCode()
- 为什么需要hashCode()方法和equals()方法
equal():判断两个对象是否相同(一般是内容相同)
hashCode():用来在散列存储结构中确定对象的存储地址
,从而实现快捷查找
。 - 为什么需要重写hashCode()方法和equals()方法
我们经常会希望两个不同对象的某些属性值相同时
就认为他们相同,所以我们要重写equals()方法。而按照原则,我们重写了equals()方法,也要重写hashCode()方法。 - 如何重写hashCode()方法和equals()方法
- JavaSE 8 Specification中对equals()方法的说明:
- 自反性:A.equals(A)要返回true;
- 对称性:如果A.equals(B)返回true, 则B.equals(A)也要返回true;
- 传递性:如果A.equals(B)为true, B.equals©为true, 则A.equals©也要为true. 说白了就是 A = B , B = C , 那么A = C;
- 一致性:只要A,B对象的状态没有改变,A.equals(B)必须始终返回true;
- A.equals(null) 要返回false;
- 在Java API文档中关于hashCode方法有以下几点规定(原文来自java深入解析一书)
-
在java应用程序执行期间,如果在equals方法比较中所用的信息没有被修改,那么在同一个对象上多次调用hashCode方法时必须一致地返回相同的整数。如果多次执行同一个应用时,不要求该整数必须相同。
-
如果两个对象通过调用equals方法是相等的,那么这两个对象调用hashCode方法必须返回相同的整数。
-
如果两个对象通过调用equals方法是不相等的,不要求这两个对象调用hashCode方法必须返回不同的整数。但是程序员应该意识到对不同的对象产生不同的hash值可以提供哈希表的性能。
重写了equals()方法也要重写hashCode()方法,这是因为要保证上面所述的第二个和第三个原则
-
- JavaSE 8 Specification中对equals()方法的说明:
参考文献
https://blog.csdn.net/u010983881/article/details/49762595 hashmap和hashtable的区别
https://www.nowcoder.com/questionTerminal/95e4f9fa513c4ef5bd6344cc3819d3f7 fast-fail机制和fail-safe机制
https://www.jianshu.com/p/1c2d31b1f69e 为什么需要fast-fail(快速失败)机制
https://github.com/CyC2018/CS-Notes/blob/master/notes/Java 容器.md 容器
https://blog.csdn.net/javazejian/article/details/51348320 重写equal()时为什么也得重写hashCode()
https://blog.csdn.net/xlgen157387/article/details/63683882 为什么要重写hashCode()方法和equals()方法以及如何进行重写