Java集合-基础+源码分析

	以下分析学习内容仅是个人的学习总结,都是Java集合的**基础**内容,若有错误遗漏,欢迎指正,大家一起学习。环境为 jdk8,idea2020.3。

在这里插入图片描述

集合

一、相对数组等数据结构:
·动态保存
·提供了一系列方便操作对象的方法:add、remove、set、get等
·使用集合添加、删除新元素比较方便,代码简洁。

二、集合的框架体系
Collection单列集合
Map 双列集合

interable
	collection
		list
			arraylist
			linkedlist
			vector
		set
			hashset
			linkedhashset
			treeset
map
	hashmap
	linkedhashmap
	hashtable
	properties
	treemap

(1)、collection接口

方法
	add():添加单个元素
	remove():删除指定元素
	contains():查找元素是否存在
	size():获取元素个数
	isEmpty():判断是否为空
	clear():清空
	addAll():添加多个元素
	containsAll():查找多个元素是否存在
	removeAll():删除多个元素

(2)、如何遍历集合中的元素

	1、使用iterator(迭代器)
		(1)、每个实现了collection接口的类都有Iterator方法,会返回一个interator对象,该对象可以遍历集合中的元素。 
		Iterator
			hashnext()
			next()
			remove()
			forEachRemaing()

		(2)、while遍历
			 while (iterator.hasNext()) {
       				 Object next =  iterator.next();
       			 }

		(3)、当一次遍历结束后,iterator迭代器的指针指向最后元素的位置,如果再次遍历,需要重置迭代器。没有重置执行next()会出NoSuchElementException。
		Iterator iterator = 集合.iterator();

	2、for循环增强
	for(元素类型 元素名:集合名或数组名){
	}
		(1)、底层还是调用iterator迭代器,简化版的迭代器

(3)、List接口

	1、List集合中元素有序、可重复。
	2、元素有索引,支持索引。
	3、可以根据元素的序号直接对元素进行操作。
方法
	void add(int index, Object ele)
	boolean addAll(int index, Collection eles)
	Object get(int index)
	Object set(int index, Object ele)
	int indexOf(Object obj) 返回首次出现的位置
	int lastIndexOf(Object obj) 返回末次出现的位置
	Object remove(int index) 删除指定元素并返回该元素
	List subList(int fromIndex,int toIndex) 返回字串,前闭后开

遍历方式
	1、迭代器iterator
	2、for循环增强
	3、普通for循环

(3.1)、ArrayList

ArrayList
	1、arrayList 允许空值、多个控制null
	2、arrayList 底层实现为数组
	3、arrayList **线程不安全**,但执行效率高; Vector线程安全。
	

ArrayList 的底层结构:
	1、ArrayList 维护了一个Object类型的数组elementData。
		transient Object[] elementData;
	2、创建ArrayList 对象,使用无参构造器创建时,elementData初始容量为0,第一次添加扩容到10,之后需要再次扩容,会扩容到1.5倍。
	3、使用指定大小的构造器创建时,elementData初始容量为指定的大小,之后需要扩容会扩容到1.5倍。

========================================================================

ArrayList 的底层实现过程:
(1)、add()
(一)、以无参构造器创建对象
创建空的Object类型的elementData[]数组,第一次add方法执行,首先将当前的minCapacity(目前需要的最小空间,size+1)和DEFAULT_CAPACITY(常量10)进行比较,选出最大值作为第一次扩容的大小(第一次扩容的大小为DEFAULT_CAPACITY=10决定的)。之后执行grow方法进行扩容,使用Arrays.copyOf()扩容复制到elementData数组,最后执行elemetData[size++] = e 赋值。扩容完成。
使用Arrays.copyOf()能够保存之前存在的数据。modCount记录对集合对象的操作次数。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
+
(二)、有参构造(指定大小)创建对象
除了创建elementData数组的大小不同,其他与无参构造的过程大致相同。
在这里插入图片描述

========================================================================

(3.2)、Vector

	特性:底层也是Object类型的elementData数组,无参构造默认大小为10,之后扩容都为2倍。
	线程安全,每个方法都有synchronized修饰,但是效率不够ArrayList高。

·扩容方法:
在这里插入图片描述

(3.3)、LinkedList

++++++++++++++++++
(3.3.1)、底层结构
·底层为 双向链表+双端队列
·元素可重复、可为null、可添加任意元素。
·线程不安全。
++++++++++++++++
(3.3.2)、底层操作机制
·底层维护一个双向链表
·LinkedList中维护了两个属性 first 和 last 分别指向头节点和尾节点,每个节点又维护了三个属性:prev、next、item。
·LinkedList 元素的添加和删除,效率较高。
+++++++++++++++++
(3.3.3)、底层源码
·无参构造创建对象
LinkedList list = new LinkedList();
在这里插入图片描述

·add()方法
首先会对传入的参数进行装箱(如果需要的话)
执行 linkLast() 方法,将元素添加到表尾。

   void linkLast(E e) {
   
        final Node<E> l = last;
        final Node<E> newNode = new Node<>(l, e, null);
        last = newNode;
        if (l == null)
            first = newNode;
        else
            l.next = newNode;
        size++;
        modCount++;
    }

·remove()方法
LinkedList的remove()方法会删除链表中的首节点;

public E remove() {
   
        return removeFirst();
    }

 public E removeFirst() {
   
        final Node<E> f = first;
        if (f == null) //当链表为空链表时,报错
            throw new NoSuchElementException(); 
        return unlinkFirst(f);
    }

 private E unlinkFirst(Node<E> f) {
   
        // assert f == first && f != null;
        final E element = f.item; //取出首节点的item,返回
        final Node<E> next = f.next;
        f.item = null;
        f.next = null; // help GC
        first = next;
        if (next == null)
            last = null;
        else
            next.prev = null;
        size--;
        modCount++;
        return element;
    }

+++++++++++++++++++++
(3.3.4)、遍历
·迭代器
·增强for循环
·普通for循环
+++++++++++++++++++++

————————————————————————————————————————————
(4)、ArrayList 和 LinkedList 如何选择
增删:LinkedList
改查:ArrayList

(5)Set

	1、无序,没有索引。
	2、元素不可重复,null 只能有一个。
	3、遍历可以使用:迭代器iterator、增强for循环。

(5.1)HashSet 源码分析

(一)、构造器创建对象
底层为hashmap实现

  public HashSet() {
   
        map = new HashMap<>();
    }

(二)、add方法
* 注意add方法如何排除重复元素
* 注意hashcode的形成
在这里插入图片描述

//执行HashSet
  public HashSet() {
   
        map = new HashMap<>();
    }

//在add方法执行之前,如需要会先对元素进行装箱操作,对象为Object或者其子类

//执行add()
private static final Object PRESENT = new Object(); //主要的作用是 占位,因为HashSet底层是用HashMap实现的,<Key,Value>的形式中Value被固定设定为PRESENT这个常量,Key即存储Set中的元素。
public boolean add(E e) {
   
        return map.put(e, PRESENT)==null;
    }

//
public V put(K key, V value) {
   
        return putVal(hash(key), key, value, false, true);
    }
 static final int hash(Object key) {
   
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
        //key==null,hash为0;
        //key!=null,hash为h^(h>>>16).如何理解?
        //源码注释:计算 key.hashCode() 并将散列的较高位(异或)传播到较低位。
        //我的理解是:由于在计算index时,是使用(n-1)&hash的方式,所以index的值就只取决于hash值的低位,而计算hash值时,通过h^(h>>>16),
        //将高位和低位进行异或,将高位的散列扩散到低位,就让hash值不仅仅是靠低位来决定,也有高位来进行干预。所以说:将散列的较高位异或传播到较低位。
        
    }
    
//这里示范进入的是Integer的hashcode方法,整形的hashcode就是自身。
@Override  
    public int hashCode() {
   
        return Integer.hashCode(value);
    }

//核心,计算index,然后赋值
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
   
        Node<K,V>[] tab; Node<K,V> p; int n, i;//临时辅助变量tab、p、n、i
        //table是HashMap中的一个属性,类型为 Node[]
        //如果当前table为null或者table大小为0,则进行第一次扩容,默认大小为16.
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
      //(1)根据key的hash值与table表的长度-1(16-1)进行&运算,获取index
      //(2)如果当前位置为null,则直接newNode传入
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
      //当前位置不为空,进入else
        else {
   
            Node<K,V> e; <
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值