2025.02.18笔记 ~ langhai

林书豪
2025-02-18 11:57:28
2025.02.18笔记 浪海值:60度
文章标签:java基础面试题
文章摘要:2025.02.18笔记
使用新的显示器:新的显示器 如果遇到图片单击即可放大/缩小。

2025.02.18笔记

ArrayList源码分析

// 默认的初始容量
private static final int DEFAULT_CAPACITY = 10;

// 存储ArrayList元素的数组缓冲区
transient Object[] elementData;

// ArrayList的大小
private int size;

    // 带参构造函数
    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);
        }
    }

    // 无参构造函数
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }
    
    // 带参构造函数
    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;
    }
    
    // 计算是否需要扩容
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
    
    // 扩容方法
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        // 从这里可以清楚看到 增加原来1.5倍的容量
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
        // 第一次添加元素 初始化的数组长度是10
            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);
    }
    
    

ArrayList底层是动态数组实现的,初始化容量为0,当第一次添加数据的时候容量变为10。扩容的话就是原来的1.5倍,每次扩容都需要进行数组的拷贝。每次在添加元素的时候,会判断是否有足够的容量进行存储。(当前数组已经使用的长度 + 1  是否大于当前数组的长度)

如果构造函数指定了容量,就是调用有参构造函数,例如 new ArrayList(10),这种情况下是直接创建数组的,并没有进行扩容。


ArrayList LinkedList

ArrayList是动态数组的数据结构 LinkedList是双向链表的数据结构。

ArrayList可以按照下标查询,时间复杂度是O(1),内存地址是连续的,可以根据寻公式查找。


CAS:Compare And Swap 比较在交换。乐观锁思想的体现,在没有锁的情况下,保证共享数据的原子性。


volatile:保证线程间的可见性 禁止进行指令重排序(其中写、读屏障来实现)。


AQS:抽象队列同步器,构建锁或者其他同步组件的基础框架。内部维护了一个先进先出的双向队列,以及一个属性状态,来判断是否是无锁的状态。这个属性值,操作的时候需要用到CAS,来保证多线程情况下的原子性。


垃圾回收:如果一个对象没有任何的引用指向他,这个对象就有可能被回收。

有两种方法来判断对象是不是垃圾:第一种就是引用计数法,第二种就是可达性分析算法。

引用计数法:对象被引用次数,引用次数为0,代表这个对象可以被回收。如果出现循环引用,引用计算法会失效,会出现内存泄漏的情况。

可达性分析算法:现在虚拟机采用的算法。有一个GC Roots节点为初始节点,形成一个引用链,如果在这个引用链上找不到该对象,就表示可以回收。

哪些对象可以被作为GC Root:虚拟机栈中引用的对象 方法区中类静态属性引用的对象 方法区中常量引用的对象 本地方法栈中的JNI(Native方法)引用的对象。


垃圾回收算法:标记清除算法 复制算法 标记整理算法。

标记清除算法:先根据可达性分析算法找到垃圾,对垃圾进行标记,然后进行回收垃圾。此算法标记和清除的速度比较快,但会出现内存碎片,导致内存不连贯。

标记整理算法:解决了标记清除算法内存碎片化的问题。需要对对象进行移动,效率低。

复制算法:清理之后没有内存碎片,分配2块内存空间,在同一个时刻,只能使用一半,内存使用率较低。


分代回收:新生代 1/3的空间占用 和 老年代 2/3的空间占用。

新生代里面就是包含 一个伊甸园区 Eden 和 幸存者区 from to。这三个是 8 :1 :1的空间占用关系。

新创建的对象都会被分配到伊甸园区 Eden,当幸存者区经过最多15次对象回收之后,会晋升到老年区。(幸存者区域不足 或者 对象太大 会导致提前晋升到老年代区域)


MinorGC:发生在新生代的垃圾回收,会造成短暂的STW。

FullGC:新生代 + 老年代完整垃圾回收,暂停的STW比较长。

MixedGC:新生代 + 老年代 部分区域进行垃圾回收,G1垃圾回收器的特性。

STW的就是指暂停应用程序的时间,需要等待。Stop - The - World。


设计模式

工厂模式:优点解耦

   简单工厂模式:增加新产品时候,还是需要修改工厂类的代码。

   工厂方法模式:

           主要角色:抽象工厂 抽象产品 具体工厂 具体产品

           用户只需要知道具体工厂的名称就能获取对应的产品,不需要知道产品的具体创建过程。

           系统在添加新产品的时候,需要提供具体的产品类和对应的具体工厂类,是满足开闭原则的。

   抽象工厂模式:

           工厂方法模式的升级版本,能够创建多个等级的产品。

















提交评论