Java源码阅读学习后的浅析和感悟(JDK篇)(持续更新)

Java源码阅读学习后的浅析和感悟(JKD篇)

- 为什么阅读源码

一、感觉现在学习Java就是在学她的各种API如何调用,时间长了就觉得Java很枯燥失去了热情。

二、好奇这些API在底层如何实现的,就比如pow(a,b)难道就是b个a相乘?顺便再记个笔记方便复习。

三、更想学习这些大佬们的思路,到底是什么样的人才能搞出来这些东西!

四、个人原因,可能是感情问题哈哈哈哈哈,我突然发现我在感情上一旦出现情绪波动,唯一能转移情绪的可能就是技术了!

集合框架类

- 为什么会要引入集合

答:为了更方便更高效的存储多个数据。

在初学的时候,我们都知道在集合出现之前方便存储多个数据的是数组,但是它总归有自己的局限性:

1.长度,在存储对象时由于长度的不确定性使得数组不太适用。因为数组一旦指定了长度就无法更改。

2.存储特性,顺序存储且可重复。故对于需要无序的或需要去重的存储就带来了极大的不便。

3.增加、删除,在增删时效率太低。在我们学数据结构中可知,数组是顺序表的结构,数组除了在末尾删除时不需要移动其他元素,在别的地方都需要。

- 集合结构图(部分)

在这里插入图片描述

ArrayList集合源码分析

- 扩容机制

如何扩容:
		一、ArrayList中创建了一个Object型的数组elementData[],往后的绝大多数操作都是以elementData数组为基础。

	    二、当ArrayList对象是用ArrayList()方法被创建时,elementData的初始容量为 0,第一次向里面添加元素时,其容量会扩容到 10,如果需要再次扩容,则扩容的容量时当前容量的1.5倍。

	    三、当ArrayList对象是用ArrayList(int)方法被创建时,则容量为指定容量大小,如果再次扩容,容量是前一次的1.5倍。
	    
下面给出所要用到的方法、其解释和自己学习后的看法。(变量size-->索引)	    
  • 构造方法
// ArrayList(int)
public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }
    
//ArrayList()
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

//ArrayList(Collection<? extends E> c)
public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();
        if ((size = elementData.length) != 0) {
            // c.toArray might (incorrectly) not return Object[] (see 6260652)
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
            // replace with empty array.
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }
  • 插入数据

public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

   
public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  // Increments modCount!!
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
- 关键方法解释(DEFAULTCAPACITY_EMPTY_ELEMENTDATA–>默认为空的elementData数组)
1.private void ensureCapacityInternal(int minCapacity)
private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }
该方法用于计算elementData的最小容量。
2.private static int calculateCapacity(Object[] elementData, int minCapacity)
private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }
注:DEFAULT_CAPACITY默认扩容容量为 10
该方法 1.先判断这个数组的容量是否为 0,如果是 0,说明他用了无参构造器创建了该对象,再用了Matn.max(a,b)去最大值的方法返回给函数头。如果不为 0,则直接返回给函数头。
该方法的目的就是为了判别创建该对象时是否指定了其容量。
3.private void ensureExplicitCapacity(int minCapacity)
private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
该方法为了明确最小容量是否足够当前的数据进入。
if (minCapacity - elementData.length > 0) 这段话的意思就是如果最小容量(其实就是指当前集合内有效元素的个数)大于了数组的长度说明容量不够了,需要扩容了故他就往下走,走到grow(minCapacity)方法中去。
4.private void grow(int minCapacity)★
private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
这一步才是真正对其进行扩容的步骤。
这一段的逻辑其实并不难但是很妙!
int oldCapacity = elementData.length  他把数组的长度给了这个扩容前的容量(oldCapacity)
int newCapacity = oldCapacity + (oldCapacity >> 1)  这段话是先把扩容前的容量扩容1.5呗然后赋给扩容后的容量(newCapacity ) 这里的位运算就用的很妙 oldCapacity >> 1 == oldCapacity / 2
if (newCapacity - minCapacity < 0)
        newCapacity = minCapacity;  这段话就是进行修补了,如果新容量比最小容量还小,那还不如用这个最小容量。
if (newCapacity - MAX_ARRAY_SIZE > 0)
        newCapacity = hugeCapacity(minCapacity); 这句话应该就是防止数组无限扩容。       
elementData = Arrays.copyOf(elementData, newCapacity);  最后用了这个拷贝的方法,他在保留了原有数据的基础上再对数组进行扩容。        
5.总结
第一次学习源码,真的是满嘴卧槽,很多地方太妙了。虽然自己的水平太难达到这种地步,但是看大牛前辈们留下的精华也是一种享受!!但是自己觉得这里面也有些不足,比如在用add()方法时,他每次都对当前容量进行判断是否需要扩容,如果我时批量添加元素也就是我添加n次他就判断n次,这样可能就会使得效率略低,做了一些无用功,但是还是不妨碍大佬们的这些发光的技术精华!(个人感受)

LinkedList集合源码分析

- 增删改查分析

LinkedList本质上就是一个(双向)链表,其优点:
	一、增加和删除的操作效率高,相比于数组,其时间复杂度为O(n)而链表则为O(1)

    二、不受大小限制,拓展性强。

	三、内存利用率高,只有在创建时才占用内存,不会对内存造成浪费。
- 链表基本插入删除操作演示(动图)

插入
在这里插入图片描述
删除
在这里插入图片描述

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

孔表表uuu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值