集合
集合的分类和特点
单列集合的继承关系
map集合的继承关系
各个特点的简单总结
Concurrenthashmap 线程安全,高效的键值对集合。
底层是哈希表,线程安全的实现原理,JDK1.7之前是通过锁分段的技术(Segment),但是只有16个分段最多支持16个线程并发。
1.8之后采用CAS乐观锁和Synchronized悲观锁两种方式实现,存放hashcod值的数组的线程安全采用CAS乐观锁的方式来保证,而数组节点下的链表和红黑树的线程安全采用synchroniezd悲观锁。
常用的方法
单列集合常用的方法很多都是Collection顶端接口中的,还有就是list集合关于索引的一些方法,以及TreeSet集合中关于头元素和尾元素的一些方法。
Collection中常用的方法
- public boolean add(E e): 把给定的对象添加到当前集合中 。
- public boolean remove(E e): 把给定的对象在当前集合中删除。
- public boolean contains(Object obj): 判断当前集合中是否包含给定的对象。
- public boolean isEmpty(): 判断当前集合是否为空。
- public int size(): 返回集合中元素的个数。
- public Object[] toArray(): 把集合中的元素,存储到数组中
- public void clear() :清空集合中所有的元素。
List中常用的索引方法
- int indexOf(Object o):返回第一次出现o元素所在的索引位置,没有返回-1
- E set(int index , E element):替换索引位置的元素
- List subList(int fromIndex,int toIndex):返回两索引之间的元素集合(包左不包右)
TreeSet中常用的方法
- E first():返回此集合中当前的第一个元素(默认最小)
- E last():返回此集合中最后的元素(默认最大)
- E floor(E e):返回集合中小于或等于指定元素中最大的元素
- E lower(E e):返回集合中小于指定元素中最大的元素
- E higher(E e):返回集合中大于指定元素中最小的元素
键值对集合常用方法
- public V put(K key, V value): 把指定的键与指定的值添加到Map集合中。
- public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
- public V get(Object key): 根据指定的键,在Map集合中获取对应的值。
- boolean containsKey(Object key): 判断集合中是否包含指定的键。
- public Set keySet(): 获取Map集合中所有的键,存储到Set集合中。
- public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。
集合的遍历
单列集合的遍历有两种办法
1.迭代器iterator
因为不同的集合有不同的数据结构所以为了方便的取出数据定义了一个迭代器接口,由每个集合自己来进行实现(是集合的内部类)迭代器中主要有两个方法
- boolean hasNext() 如果仍有元素可以迭代,则返回 true。判断集合中是否含有元素 有返回true,没有返回false
- E next() 返回迭代的下一个元素。 取出集合中的下一个元素
迭代器的实例由单列集合自己创建,调用Collection中的Iterator<E> iterator() 返回在此 collection 的元素上进行迭代的迭代器。
简单的例子
public static void main(String[] args) {
Collection<String> coll = new ArrayList<>();
coll.add("詹姆斯"); coll.add("科比"); coll.add("姚明"); coll.add("欧文");coll.add("艾弗森");
Iterator<String> it = coll.iterator();
while (it.hasNext()){
//判断集合中是否还有元素 //有元素,取出元素
String s = it.next();
System.out.println(s);
}
2.增强for
增强for的内部对迭代器进行了封装可以直接使用
private static void show04() {
ArrayList<Person> list = new ArrayList<>();
list.add(new Person("柳岩",18));
list.add(new Person("迪丽热巴",18));
list.add(new Person("古力娜扎",18));
list.add(new Person("赵丽颖",18));
for(Person p : list){
System.out.println(p);
}
}
键值对集合map的遍历
1.key单列集合方法所使用的方法
- Set keySet() 把所有的key取出来存储到一个Set集合中 V
- get(Object key) 根据key获取value值
就是把key存到set集合再遍历set集合然后获取value完成map遍历
2.entry键值对集合方法
- Set<Map.Entry<K,V>> entrySet()返回此映射中包含的映射关系的 Set 视图。 Entry对象中的方法:
- K getKey() 返回与此项对应的键。
- V getValue() 返回与此项对应的值。
entry存的是一个键值对,其他的基本和上个方法类似。
集合的数据结构
数组(ArrayList)
扩容操作:如果默认是空参构造的话创建的第一个数组的长度是10,我们也可以指定长度,当我们的添加数据大于数组长度时会首先创建一个原数组长度1.5倍的数组(如果原数组长度是奇数的话就比1.5少一点)copy原数组的数据然后再添加新数据。
链表(LinedList)
扩容机制:链表是节点连接的,所以扩容就是直接添加节点。
红黑树(TreeSet,TreeMap)
扩容机制:添加叶子节点
哈希表(HashSet,HashMap,HashTable)
扩容机制:其中HashSet和HashMap 的哈希表默认都是16,扩容因子是0.75,扩容方式都是原来的一倍。但是HashTable的哈希表默认是11,扩容因子0.75,扩容方式是原容量的一倍加一。
集合常见的一些问题?
set和list 的区别?
list具有有序,可重复,带有索引的方法的特点,而set方法元素不可重复,没有带有索引的方法(set集合严格说不能说是无序的,treeSet和LinkedHashSet都是有序的)
迭代器的并发修改异常?
迭代器在进行while循环时对集合长度进行修改(数据进行增加或者删除的操作)时会发生的异常。
出现案例
Iterator<String> it = list.iterator();
//使用迭代器中的方法hasNext和next遍历集合
while (it.hasNext()){
String s = it.next();
System.out.println(s);
/* 增加一个判断,如果取出的元素s是"ccc" 就给集合添加一个元素"itcast" 注意:判断时要把已知的值写在前边,防止空指针异常 */
if("ccc".equals(s)){
//list.add("itcast");
}
}
解决办法:
1.遍历集合的同时,不对集合进行长度修改
2.Iterator迭代器有一个子接口ListIterator,在ListIterator中定义了往集合中添加元素 和删除元素的方法public interface ListIterator<E>extends Iterator<E>
- void add(E e) 往集合中添加元素
- void remove() 移除next方法返回的元素
注意:
1.如果要使用迭代器中的add|remove方法,往集合中添加元素|删除元素 就相当于集合和迭代器商量好了,可以添加和删除,迭代器就不会抛出并发修改异常了
2.ListIterator迭代器只能遍历List接口下的集合,Set接口下的集合不能使用
ArrayList和LinkedList的区别?
ArrarList底层是数组具有查询快增删慢的特点,具有索引的方法,LinkedList底层是链表具有查询慢增删块的特点,没有索引方法。
HashSet和TreeSet的区别?
hashset底层是哈希表,无序的,treeset底层是红黑树,可以用比较器comparator来决定排序规则(默认升序 o1-o2)
hashMap和hashTable的区别?
hashmap可以有一个key为null,多个value为null,线程不安全,效率比较高。hashtable不可以出现bull,线程通过synchronized来实现线程安全,效率比较低。
HashMap和TreeMap的区别?
hashmap底层是哈希表,无序。treemap底层是红黑树,comparator比较器来决定排序(默认升序)