集合(从实战应用到原理分析)

一:集合应用

1.1:集合类架构图(掌握)

在这里插入图片描述

Collection是单列集合父接口。
	List存取有序,有索引,能存储重复元素。
	Set存取无序,无索引,按照某种方式。
Map是双列集合父接口。

1.2:常用方法(留个印象)

1.2.1:Collection(所有子类对象都能用该方法)

add(E e)
remove(E e)
size()
clear()    //将集合清空
contains(E e)
toArray()   //将集合转为数组
isEmpty()   //集合是否为空
Iterator<E> iterator()
boolean containsAll(Collection<?> c)
boolean addAll(Collection<? extends E> c)
boolean removeAll(Collection<?> c)

1.2.2:List

a:List接口常用方法

add(int Index,E e);
remove(int Index);
get(int index);

b:LinkedList常用方法(头和尾相关方法)

public void addFirst(E e) :将指定元素插入此列表的开头。
public void addLast(E e) :将指定元素添加到此列表的结尾。 
public E getFirst() :返回此列表的第一个元素。 
public E getLast() :返回此列表的最后一个元素。 
public E removeFirst() :移除并返回此列表的第一个元素。 
public E removeLast() :移除并返回此列表的最后一个元素。

c:注意:

ListIterator<Integer> iterator = list1.listIterator();是list集合特有的。

1.2.3:Collections工具类常用方法

public static void shuffle(List<?> list) 打乱顺序 :打乱集合顺序。
public static <T> void sort(List<T> list) :将集合中元素按照默认规则排序。
public static <T> void sort(List<T> list,Comparator<? super T> ) :将集合中元素按照指定规则排

1.2.4:Map

public V put(K key, V value) : 把指定的键与指定的值添加到Map集合中。
public V remove(Object key) : 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的 值。
public V get(Object key) 根据指定的键,在Map集合中获取对应的值。 
public Set<K> keySet() : 获取Map集合中所有的键,存储到Set集合中。 
public Set<Map.Entry<K,V>> entrySet() : 获取到Map集合中所有的键值对对象的集合(Set集合)。

Entry键值对对象
public K getKey() :获取Entry对象中的键。 
public V getValue() :获取Entry对象中的值。

1.3:集合遍历(理解)

1.3.1:List(ArrayList,LinkedList)集合遍历

  1. for循环 for (int i = 0; i < list.size(); i++){}
a:删除遍历过程中元素园路
	在遍历的时候可以进行元素删除。但是每次删除一个一个元素的时候,该元素之后的元
素下标就会向前移动一位,所以在删除一个元素,让i值进行减一。采用倒叙遍历就可以解
决这个问题。

b:实战,去除集合重复元素
	例子1:
		List<String> list = new ArrayList();
		//从头取出第一个元素,然后和后面的元素对比,一样的删除。
	 	 for (int i = 0; i < list.size() -1; i++) {
            for (int c = list.size() - 1; i > i; c--) {
                if (list.get(i).equals(list.get(c))) {
                    list.remove(c);
                }
            }
        }
	 例子2(链表,解题思路适合链表结构):
	 List<String> list = new LinkedList();
		  //判断集合中是否含有元素,含有,删除。然后再判断集合中是否还含有刚才删除的元素,含有,代表该元素重复了。没有了,代表该元素没有重复,将该元素添加到集合中。
	      for (int i = list.size() -1; i > 0 ; i--) {
	          if(list.contains(list.get(i))){
	              Integer remove = list.remove(i);
	              if(!list.contains(remove)){
	                  list.add(i,remove);
	              }
	          }
	      }
  1. 增强for循环(底层是遍历器)
  2. 迭代器
    a:遍历原理:
    在这里插入图片描述
迭代器遍历集合的时候(遍历开始的时候,指针指向第一个元素前),先判断该指针后是否
含有元素,如果含有指针向后移动一位,然后取出元素,然后再次判断指针后是否含有元
素,如果含有元素取出元素,没有元素遍历结束。

b:遍历过程中删除元素

在遍历的过程中删除元素,不能使用集合的删除方法,得使用迭代器的删除方法(iterator.remove();)。要是并发条件需要对Iterator对象加锁。
实例:
  while (iterator.hasNext()) {
         iterator.next();
         iterator.remove();
     }
  //iterator.hasNext(),集合中是否含有元素
  //iterator.next();取出元素,将指针向后移动一位
  //迭代器遍历元素的时候,指针指向头,不指向任何元素,所以在在删除时候,必须调用next()元素。

c:注意:

在遍历集合,集合和迭代器同时持有同一个对象,当集合在添加,和删除集合元素时(修改呢),迭代器并不知道,
所以会发生并发修改异常。(迭代器遍历和增强for循环)

1.3.2:Set集合遍历

  1. 迭代器(和List遍历一样)
  2. 增强for循环(和List遍历一样)

1.3.3:Map集合遍历

例一:

	// 获取 所有的 entry对象 entrySet 
	Set<Entry<String,String>> entrySet = map.entrySet(); // 遍历得到每一个entry对象 
	for (Entry<String, String> entry : entrySet) { 
		String key = entry.getKey(); 
		String value = entry.getValue(); 
		System.out.println(key+"的CP是:"+value); 
	}

例二:

Set<String> keys = map.keySet(); // 遍历键集得到每一个键 
for (String key : keys) { //key 就是键 
	//获取对应值
	 String value = map.get(key); 
	 System.out.println(key+"的CP是:"+value);
 }

二:集合原理

2.1:ArrayList和Vector(理解)

  1. ArrayList
底层是数组实现的,线程不安全、效率高。

初始化容量默认是10,在新增每一个元素都会对索引正确性进行判断,是否扩容进行判断。集合进行扩容的时候,就
是使用arraycopy(Object src,  int srcPos,Object dest, int destPos,int length),方法进行数组
复制。删除元素时,判断索引是否和法,原理是把被删除元素右边的元素左移,方法同样是使用System.arraycopy
进行拷贝。修改元素仅仅需要检查元素下标。

多个线程对同一个ArrayList集合进行访问,至少至少又一个线程改变集合结构,所以为了保证数据同步List<Integer>
list = Collections.synchronizedList(new ArrayList<Integer>());

Collections.synchronizedList()优势:
	Vector对大部分方法都加锁了,效率很低。
	Collections.synchronizedList(new ArrayList<Integer>()),仅仅在新增编辑删除加锁,对遍历的时候没加锁。
  1. Vector
底层数组。大部分方法都使用了synchronized修饰,线程安全,效率低。

2.2:LinkedList(理解)

2.2.1:底层数据结构(双链表结构)

在这里插入图片描述

是线程不安全的。
在进行删除,遍历找到元素,删除元素并修改前后元素索引。
在新增时候,遍历找到指定索引,添加元素,修改前后元素索引。

2.3:HashSet、TreeSet和LinkedHashSet(理解)

2.3.1:HashSet

a:底层数据结构:

底层就是HashMap,原理图看HashMap原理图。

b:添加元素流程
在这里插入图片描述
c:注意

当集合中存储的是系定义对象,要重写hashCode()方法和eques()。

2.3.2:TreeSet(了解)

a:原理

TreeSet底层数据结构基于TreeMap,红黑树。
可以按照自然顺序,也可以自定义排序。(和HashSet去重不一样)

b:自然顺序(Comparable)

TreeSet类的add()方法中会把存入的对象提升为Comparable类型
调用对象的compareTo()方法和集合中的对象比较(返回0,不保存元素)
根据compareTo()方法返回的结果进行存储

c:比较器顺序(Comparator)

创建TreeSet的时候可以制定 一个Comparator
如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的规则比较
add()方法内部会自动调用Comparator接口中compare()方法排序(返回0,不保存元素)
调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

2.3.3:LinkedHashSet

底层是链表+哈希表,相对于HashSet,存取有序。

2.4:HashMap、HashTable(理解)

2.4.1:HashMap

a:HashMap底层图
在这里插入图片描述

默认初始容量为16(为2的n次方,减少hash碰撞,让数据散列更加均匀),负载因子0.75。
当新增元素超过初始容量*负载因子,则进行扩容,2倍进行扩容。

是线程不安全。

注意:

HashMap集合中key和value都可以为null,当key值一样时候,value值会覆盖。
HashTable是都不能为null。
TreeMap是key不能为null,value可以为null。

2.4.2:HashTable(被HashMap取代)

是线程安全的。底层数据结构和HashMap一致。
HashTable里使用的是synchronized关键字,这其实是对对象加锁,锁住的都是对象整体,
当Hashtable的大小增加到一定的时候,性能会急剧下降,因为迭代时需要被锁定很长的
时间。

2.4.3:ConcurrentHashMap(重点、重点、重点)

a:内部结构

ConcurrentHashMap类包含两个静态内部类,HashEntry和Segment。HashEntry用来封装
映射键值对。Segment用来充当锁的角色,每一个Segment守护散列映射表的若干个桶。
每个桶由若干个Segment组成。每一个ConcurrentHashMap的实例,由若干个Segment对
象组成数组。

b:描述

和HashMap功能基本一致,主要为了解决HashMap线程不安全问题。

JDK7基本设计理念就是切分成多个Segment块,默认是16个。每个Segment里面可以近似
看成一个HashMap,每个Segment块都有自己独立的ReentrantLock锁。java8中Segment
块换成了Node,每个Node有自己的锁,即每个Node都有自己的并发度。

2.5:LinkedHashMap和TreeMap(理解)

2.5.1:LinkedHashMap

底层数据结构是,链表+哈希表。

2.5.2:TreeMap

TreeMap底层是红黑树结构,其实也就是平衡二叉树,方便快速找到指定节点。
红黑树的插入、删除和新增的时间复杂度都是0(lgn),性能远低于hash表,但是能够按照键
值大小有序输出。
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值