ArrayList浅析

目录

  • 一、ArrayList源码
    • 1.1 迭代器
      • 1.1.1 Itr源码浅析
      • 1.1.2 ListItr源码浅析
    • 1.2 常用方法
    • 1.3 System.arraycopy
    • 1.4 ArrayList 的创建方式
  • 二、引申问题
    • 2.1 ArrayList的大小是如何增加的?
    • 2.2 什么情况下你会使用ArrayList
    • 2.3 在索引中ArrayList的增加或者删除某个对象的运行过程,效率很低吗?解释一下为什么
    • 2.4 ArrayList如何顺序删除节点
    • 2.5 ArrayList的遍历方法
  • 三、总结


一、ArrayList源码

在这里插入图片描述

首先看一下ArrayList的继承关系结构图
在这里插入图片描述

ArrayList的类声明

public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{

1.1 迭代器

ArrayList源码中有一个内部类ListItr
ListItr是什么?---->官方注释:AbstractList的优化版本:ListItr

    /**
     * An optimized version of AbstractList.ListItr
     */
    private class ListItr extends Itr implements ListIterator<E> {
        ListItr(int index) {
            super();
            cursor = index;
        }

        public boolean hasPrevious() {
            return cursor != 0;
        }

        public int nextIndex() {
            return cursor;
        }

        public int previousIndex() {
            return cursor - 1;
        }

        @SuppressWarnings("unchecked")
        public E previous() {
            checkForComodification();
            int i = cursor - 1;
            if (i < 0)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i;
            return (E) elementData[lastRet = i];
        }

        public void set(E e) {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.set(lastRet, e);
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        public void add(E e) {
            checkForComodification();

            try {
                int i = cursor;
                ArrayList.this.add(i, e);
                cursor = i + 1;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }
    }

可以看到 ListItr 继承自Itr,那么Itr长啥样子呢?
官方注释:Itr,一个AbstractList.Itr的优化版本

    /**
     * An optimized version of AbstractList.Itr
     */
    private class Itr implements Iterator<E> {
        int cursor;       // index of next element to return
        int lastRet = -1; // index of last element returned; -1 if no such
        int expectedModCount = modCount;

        // prevent creating a synthetic constructor
        Itr() {}

        public boolean hasNext() {
            return cursor != size;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            checkForComodification();
            int i = cursor;
            if (i >= size)
                throw new NoSuchElementException();
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            cursor = i + 1;
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            checkForComodification();

            try {
                ArrayList.this.remove(lastRet);
                cursor = lastRet;
                lastRet = -1;
                expectedModCount = modCount;
            } catch (IndexOutOfBoundsException ex) {
                throw new ConcurrentModificationException();
            }
        }

        @Override
        public void forEachRemaining(Consumer<? super E> action) {
            Objects.requireNonNull(action);
            final int size = ArrayList.this.size;
            int i = cursor;
            if (i < size) {
                final Object[] es = elementData;
                if (i >= es.length)
                    throw new ConcurrentModificationException();
                for (; i < size && modCount == expectedModCount; i++)
                    action.accept(elementAt(es, i));
                // update once at end to reduce heap write traffic
                cursor = i;
                lastRet = i - 1;
                checkForComodification();
            }
        }

        final void checkForComodification() {
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

1.1.1 Itr源码浅析

可以在上面看到Itr实现了Iterator迭代器接口,实现了四个方法hasNext()next()remove()forEachRemaining()

  • int cursor;:表示下一个要返回的元素的索引。
  • int lastRet = -1;:表示最后一个返回的元素的索引;如果没有返回过元素,则为 -1。
  • int expectedModCount = modCount;:用于检查在迭代过程中是否有并发修改的情况。
  • Itr():私有构造方法,用于防止生成合成构造函数。
  • public boolean hasNext():判断是否还有下一个元素待返回。
  • public E next():返回下一个元素,并将游标向后移动一个位置。
  • public void remove():从列表中移除上一个返回的元素。
  • public void forEachRemaining(Consumer<? super E> action):对列表中剩余的元素执行指定操作。
    其他方法:
  • checkForComodification():检查在迭代过程中是否有并发修改。

在hasNext() 方法中:
判断游标和数组size大小是否相等,不相等则返回true,表示仍有下一个元素。

在 next() 方法中:
首先检查是否有并发修改(调用 checkForComodification() 方法)。
获取当前游标位置 i,检查是否超出列表大小,若超出则抛出 NoSuchElementException 异常。
获取 ArrayList 的元素数组 elementData。
若游标位置超出数组长度,则抛出 ConcurrentModificationException 异常。
将游标后移一位,返回当前元素,并更新 lastRet 为当前索引 i。

在 remove() 方法中:
检查是否有上一个元素被返回,若没有则抛出 IllegalStateException 异常。
检查是否有并发修改。
尝试从 ArrayList 中移除上一个返回的元素,更新游标和 lastRet,以及 expectedModCount。
若捕获到 IndexOutOfBoundsException 异常,则抛出 ConcurrentModificationException 异常。

1.1.2 ListItr源码浅析

Itr仅仅是实现了迭代器接口, 而ListItr继承自 Itr 类并实现了 ListIterator< E> 接口,用于提供对 ArrayList 的列表迭代器功能。以下是对代码中关键部分的详细解释:

  • ListItr(int index):构造方法,初始化 ListIterator 的游标位置为指定的索引 index。
  • public boolean hasPrevious():判断是否还有前一个元素。
  • public int nextIndex():返回下一个元素的索引。
  • public int previousIndex():返回前一个元素的索引。
  • public E previous():返回前一个元素,并将游标向前移动一个位置。
    首先检查是否有并发修改。
    计算前一个元素的索引 i,若小于 0 则抛出 NoSuchElementException 异常。
    获取 ArrayList 的元素数组 elementData。
    若索引超出数组长度,则抛出 ConcurrentModificationException 异常。
    更新游标和 lastRet,并返回前一个元素。
  • public void set(E e):将上一个返回的元素替换为指定的元素。
    检查是否有上一个元素被返回,若没有则抛出 IllegalStateException 异常。
    检查是否有并发修改,然后尝试调用 ArrayList 的 set 方法进行替换操作。
  • public void add(E e):在当前位置添加一个元素。
    检查是否有并发修改。
    尝试在当前位置添加元素,更新游标和 lastRet,以及 expectedModCount。
    若捕获到 IndexOutOfBoundsException 异常,则抛出 ConcurrentModificationException 异常。

这段代码实现了 ListIterator 的功能,允许在 ArrayList 中进行双向迭代,并提供了添加和替换元素的功能。同时,代码中也考虑了并发修改的情况,确保操作的安全性和一致性。

看一下迭代器的创建

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence), starting at the specified position in the list.
     * The specified index indicates the first element that would be
     * returned by an initial call to {@link ListIterator#next next}.
     * An initial call to {@link ListIterator#previous previous} would
     * return the element with the specified index minus one.
     *
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
        public ListIterator<E> listIterator(int index) {
        rangeCheckForAdd(index);
        return new ListItr(index);
    }

    /**
     * Returns a list iterator over the elements in this list (in proper
     * sequence).
     *
     * <p>The returned list iterator is <a href="#fail-fast"><i>fail-fast</i></a>.
     *
     * @see #listIterator(int)
     */
    public ListIterator<E> listIterator() {
        return new ListItr(0);
    }

两个重载方法 listIterator() 和 listIterator(int index),用于返回一个 ListIterator 对象,从列表中的指定位置或者从列表的起始位置开始迭代元素。


1.2 常用方法

常用方法 无非增删改查

在这里插入图片描述

    public void add(int index, E element) {
        rangeCheckForAdd(index);
        modCount++;
        final int s;
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }

添加一个元素到指定位置的列表中。
首先检查索引是否在合法范围内;
增加修改计数器 modCount;
检查并扩容;
使用 System.arraycopy 方法将原数组中的元素向后移动一个位置,并在指定位置插入新元素;
更新列表大小。

    public E remove(int index) {
        Objects.checkIndex(index, size);
        final Object[] es = elementData;

        @SuppressWarnings("unchecked") E oldValue = (E) es[index];
        fastRemove(es, index);

        return oldValue;
    }
     private void fastRemove(Object[] es, int i) {
     modCount++;
     final int newSize;
     if ((newSize = size - 1) > i)
         System.arraycopy(es, i + 1, es, i, newSize - i);
     es[size = newSize] = null;
    }

remove()
从列表中移除指定索引位置的元素。
首先检查索引是否在合法范围内;
获取移除的元素;
调用 fastRemove 方法将要移除元素后面的元素向前移动一个位置;
更新 modCount;
返回被移除的元素。

fastRemove()
快速移除指定位置元素的方法;
更新 modCount;
如果移除的不是最后一个元素,则调用 System.arraycopy 方法将后面的元素向前移动一个位置;
将数组最后位置置空;
更新列表大小。

    public E set(int index, E element) {
        Objects.checkIndex(index, size);
        E oldValue = elementData(index);
        elementData[index] = element;
        return oldValue;
    }

替换指定位置的元素为新元素;
检查索引是否合法;
获取替换之前的元素;
直接替换指定位置的元素为新元素;
返回替换之前的元素。

    public E get(int index) {
        Objects.checkIndex(index, size);
        return elementData(index);
    }

获取指定位置的元素;
检查索引是否合法;
返回指定位置的元素。


1.3 System.arraycopy

常用方法中只有增删操作使用了System.arraycopy

 public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

System.arraycopy是一个native方法,

参数解释:

src:源数组,要复制元素的数组。
srcPos:源数组中开始复制的起始位置。
dest:目标数组,要复制到的数组。
destPos:目标数组中开始粘贴的位置。
length:要复制的元素数量。

对于增删操作中的 System.arraycopy 的使用场景:

在添加元素时,通过 System.arraycopy 将特定位置之后的元素依次向后移动一个位置,为新元素腾出空间;
在删除元素时,通过 System.arraycopy 将被删除元素位置之后的元素依次向前移动一个位置,填补被删除元素的空缺;
如果是替换元素或获取元素,通常不会直接使用 System.arraycopy。

System.arraycopy 是一种底层的数组复制方法,效率较高,但只能用于数组之间的元素复制,不能用于集合之间的元素复制。在增删操作中,通过 System.arraycopy 可以较方便地实现元素的移动和填充,同时能够保证数据的完整性和位置的正确性。


1.4 ArrayList 的创建方式

public class ArrayList<E> {

	public ArrayList()
	
	public ArrayList(int initialCapacity) 
	
	public ArrayList(Collection<? extends E> c) 
	
}

通过无参构造创建时,数组的默认初始容量是10

通过指定长度参构造创建时,数组的初始容量是指定的长度

第三种在创建时,会将传入的集合数据存储到数组中,数组的初始容量是传入集合的长度


二、引申问题

2.1 ArrayList的大小是如何增加的?

在add方法中,添加元素,增长ArrayList的长度

    public void add(int index, E element) {
        rangeCheckForAdd(index);
        modCount++;
        final int s;
        Object[] elementData;
        if ((s = size) == (elementData = this.elementData).length)
            elementData = grow();
        System.arraycopy(elementData, index,
                         elementData, index + 1,
                         s - index);
        elementData[index] = element;
        size = s + 1;
    }
    private Object[] grow() {
        return grow(size + 1);
    }
    /**
     * Increases the capacity to ensure that it can hold at least the
     * number of elements specified by the minimum capacity argument.
     *
     * @param minCapacity the desired minimum capacity
     * @throws OutOfMemoryError if minCapacity is less than zero
     */
    private Object[] grow(int minCapacity) {
        int oldCapacity = elementData.length;
        if (oldCapacity > 0 || elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            int newCapacity = ArraysSupport.newLength(oldCapacity,
                    minCapacity - oldCapacity, /* minimum growth */
                    oldCapacity >> 1           /* preferred growth */);
            return elementData = Arrays.copyOf(elementData, newCapacity);
        } else {
            return elementData = new Object[Math.max(DEFAULT_CAPACITY, minCapacity)];
        }
    }

在扩容过程中,会根据当前数组的容量和需要扩容的最小增量以及首选增量来计算新的容量大小,然后使用 Arrays.copyOf 方法创建一个新的数组,并将原数组的内容复制到新数组中,最后将新数组赋值给 elementData。完成了列表的扩容操作,确保ArrayList 在添加元素时能够保持合理的容量并避免频繁扩容。


2.2 什么情况下你会使用ArrayList

使用List无非就是使用它的常用方法,而从ArrayList的增删改查源码中我们可以看出,增删过程会将数组的元素拷贝到新数组中来,再添加新数据;由于扩容需要新建数组且拷贝之前到元素到新数组中,所以说数据越多,操作越慢。

如果数据量很大的情况下,并涉及到元素的增删,会十分浪费性能,不建议使用ArrayList
ArrayList查询快,知道索引瞬间查到,适合常用来查询,修改也比较快。


2.3 在索引中ArrayList的增加或者删除某个对象的运行过程,效率很低吗?解释一下为什么

从源码已经看出按索引增加或者删除某个对象,会使用底层的arraycopy挪动数组,效率相对较低,特别是在操作的位置接近列表的开始处时。这主要是由于数组的特性决定的

  • 数组的结构:ArrayList 内部使用数组作为数据存储结构,数组是一种紧凑的数据结构,元素在内存中是连续存储的。当在数组中某个位置插入或删除元素时,需要将该位置后面的所有元素向后或向前移动,以保持索引的连续性。
  • 移动元素的开销:在数组中,移动元素的操作是比较耗时的,因为需要将大量元素复制到新的位置。如果需要在数组的开始处插入或删除元素,那么所有后续元素都需要移动,这个开销是随索引位置增大而增大的。
  • 时间复杂度:在 ArrayList 中按索引增加或删除元素的时间复杂度为 O(n),其中 n 是列表元素的总数。这是因为需要移动大量元素来维持索引的连续性,复杂度与数组中需要移动的元素数量成正比。
  • 相对于末尾的操作:相比较于在 ArrayList 的末尾增加或删除元素,按索引操作效率更低。在末尾增加或删除元素时,时间复杂度为 O(1),因为不需要移动元素,只需修改数组的长度即可。

ArrayList 在按索引增加或删除元素时效率较低,特别是在操作的位置接近列表的起始处时。如果对列表的操作需求包括频繁的按索引增加或删除元素,可能会影响程序的性能。在这种情况下,考虑使用其他数据结构如 LinkedList 等可能会更加高效。


2.4 ArrayList如何顺序删除节点

可以使用迭代器(Iterator)来遍历列表并删除满足特定条件的节点。

  • 获取 ArrayList 的迭代器对象:通过调用 ArrayList 的 iterator() 方法获取一个迭代器对象,用于遍历 ArrayList 中的元素。
  • 使用迭代器遍历 ArrayList:通过迭代器的 hasNext() 和 next() 方法来遍历 ArrayList 中的元素。在遍历过程中,可以判断当前元素是否满足删除条件。
  • 删除满足条件的节点:如果发现某个节点(元素)满足删除条件,可以调用迭代器的 remove() 方法来删除当前节点。注意:在使用迭代器的 remove() 方法之前必须先调用 next() 方法来指向要删除的元素。
  • 循环遍历直至完成:重复执行第2步和第3步,直到遍历完成所有的节点。

示例

import java.util.ArrayList;
import java.util.Iterator;

public class RemoveElementsInArrayList {
    public static void main(String[] args) {
        ArrayList<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);
        numbers.add(5);

        Iterator<Integer> iterator = numbers.iterator();
        while (iterator.hasNext()) {
            int number = iterator.next();
            if (number % 2 == 0) {  // 删除偶数节点
                iterator.remove();
            }
        }

        System.out.println(numbers);
    }
}

2.5 ArrayList的遍历方法

适用迭代器的next()方法遍历。


三、总结

ArrayList 的特点:内部是数组,有序、可重复、可存 null 值
ArrayList 的优点:尾插效率高,支持随机访问,查询快,知道索引瞬间查到,是所有集合当中查询速度最快的,
ArrayList 的缺点:中间插入、删除效率低

  • 数组一旦创建长度就固定了,在使用的过程中,不能更改,所以说数组一旦满了就得扩容,扩容的操作是先创建一个原来容量1.5倍的新数组,然后将之前数组的元素拷贝到新数组中来,再添加新数据;由于扩容需要新建数组且拷贝之前到元素到新数组中,所以说数据越多,操作越慢。
  • 同样的道理,在执行插入操作的时候,需要将插入节点之后所有的数据向后移动,执行删除操作时,有需要将删除节点之后的所有数据向前移动,由于需要移动数据,所以说操作的节点之后的数据越多,操作越慢。

数组的两个概念:大小、容量

大小指的是数组元素的个数,容量指的是数组本身的长度(最多可存储的元素个数)

ArrayList 和 LinkedList 的区别

分类ArrayListLinkedList
数据结构数组链表
查询速度
增删速度不一定不一定
存储相同数据所需要的空间
应用场景查询较多增删较多

参考链接:
java集合框架05——ArrayList和LinkedList的区别

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/706593.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

stable-diffusion 3 体验部署流程(ComfyUI)

环境准备 下载及简介 git clone https://huggingface.co/stabilityai/stable-diffusion-3-medium SD3 checkpoints&#xff1a; sd3_medium_incl_clips.safetensors (5.5GB)sd3_medium_incl_clips_t5xxlfp8.safetensors (10.1GB)sd3_medium.safetensors (4.3GB) 前两个可以…

flutter 导出iOS问题3

更新flutter版本后 macminihaomacMiniaodeMini SocialIM % flutter --version Flutter 3.7.12 • channel stable • https://github.com/flutter/flutter.git Framework • revision 4d9e56e694 (1 year, 2 months ago) • 2023-04-17 21:47:46 -0400 Engine • revision 1a6…

多款可观测产品全面升级丨阿里云云原生 5 月产品月报

云原生月度动态 云原生是企业数字创新的最短路径。 《阿里云云原生每月动态》&#xff0c;从趋势热点、产品新功能、服务客户、开源与开发者动态等方面&#xff0c;为企业提供数字化的路径与指南。 趋势热点 &#x1f947; 阿里云云原生产品负责人李国强&#xff1a;推进可…

磁盘管理 以及磁盘的分区 详细版

磁盘管理 track:磁道&#xff0c;就是磁盘上同心圆&#xff0c;从外向里&#xff0c;依次1号、2号磁道sector&#xff1a;扇区&#xff0c;将磁盘分成一个一个扇形区域&#xff0c;每个扇区大小是512字节&#xff0c;从外向里&#xff0c;依次是1号扇区、2号扇区cylinder&…

阀性能试验台测控系统响应时间的计算

阀性能试验台的测控系统响应时间是衡量系统响应速度和实时性能的重要指标。响应时间的计算涉及到信号采集、处理和执行的全过程。本文提供了一种详细的方法来计算和评估测控系统的响应时间。

分享一份 .NET Core 简单的自带日志系统配置,平时做一些测试或个人代码研究,用它就可以了

前言 实际上&#xff0c;.NET Core 内部也内置了一套日志系统&#xff0c;它是一个轻量级的日志框架&#xff0c;用于记录应用程序的日志信息。 它提供了 ILogger 接口和 ILoggerProvider 接口&#xff0c;以及一组内置的日志提供程序&#xff08;如 Console、Debug、EventSo…

每日5题Day23 - LeetCode 111 - 115

每一步向前都是向自己的梦想更近一步&#xff0c;坚持不懈&#xff0c;勇往直前&#xff01; 第一题&#xff1a;111. 二叉树的最小深度 - 力扣&#xff08;LeetCode&#xff09; /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeN…

Java基础面试重点-3

41. 简述线程生命周期(状态) 其它参考《多线程重点》中的说法。三种阻塞&#xff1a; 等待阻塞&#xff1a; 运行的线程执行o.wait()方法&#xff08;该线程已经持有锁&#xff09;&#xff0c;JVM会把该线程放入等待队列中。同步阻塞&#xff1a; 运行的线程在获取对象的同步…

u-boot(三) - 编译

一&#xff0c;u-boot编译过程总结 编译时的Makefile log&#xff1a; //链接得到ELF格式的u-boot arm-buildroot-linux-gnueabihf-ld.bfd -pie --gc-sections -Bstatic -Ttext 0x87800000 -o u-boot -T u-boot.lds arch/arm/cpu/armv7/start.o --start-group arch/arm/c…

【杂谈】-不同种类放大器及其区别

不同种类放大器及其区别 文章目录 不同种类放大器及其区别1、概述2、放大器种类2.1 如何衡量保真度2.2 如何测量放大器的效率 3、放大器分类3.1 A类放大器3.2 B 类放大器3.3 AB类放大器3.4 C类放大器3.5 其他放大器类别 1、概述 放大器是电子产品中最常用的电路之一。有几种类…

联邦学习论文阅读:2018 Federated learning with non-IID data

介绍 这是一篇2018年挂在arXiv上的文章&#xff0c;是一篇针对FL中数据Non-IID的工作。 作者发现&#xff0c;对于高度Non-IID的数据集&#xff0c;FedAvg的准确性下降了55%。 作者提出了可以用权重散度&#xff08;weight divergence&#xff09;来解释这种性能下降&#xff…

创新入门|生成式AI创新赋能优势解析,获取生成式AI知识的10大方法

生成式AI技术对员工和企业影响深远。对于员工而言&#xff0c;生成式AI能够提升工作效率&#xff0c;简化重复性任务&#xff0c;并为创意和决策提供支持。对于企业而言&#xff0c;生成式AI在产品创新、市场营销、客户服务和运营优化等方面发挥重要作用&#xff0c;帮助预测市…

亚信安慧AntDB数据库与云信达eCloud Data Master 云数据管理系统软件V4完成兼容性互认证

日前&#xff0c;湖南亚信安慧科技有限公司&#xff08;简称&#xff1a;亚信安慧&#xff09;与南京云信达科技有限公司&#xff08;简称&#xff1a;云信达&#xff09;&#xff0c;完成了AntDB数据库产品与云信达eCloud Data Master云数据管理系统软件V4的兼容性互认证。 双…

git clone 项目报“鉴权失败”的解决办法

#问题展示# git clone https://gitee.com/soaringsoft/.....git 正克隆到...... Username for https://gitee.com:...... Password for https://.....gitee.com:...... remote: [session-1440f183] Unauthorized fatal: git clone https://gitee.com/soaringsoft/.....gi…

ARM-V9 RME(Realm Management Extension)系统架构之功耗管理

安全之安全(security)博客目录导读 目录 一、系统功耗管理 1、功耗状态 2、PE功耗管理 3、系统和PE集群功耗管理 4、系统功耗状态 二、RME组件功耗管理 本节规定了RME系统的功耗管理规则。 功耗管理流程定义了系统及其组件如何在各种电源状态之间进行转换&#xff0c;以…

ansible-Role角色批量按照node_export节点,并追加信息到Prometheus文件中

文章目录 剧本功能 inventory.yaml文件定义deploy.yaml角色定义node_exporter_lock角色定义任务角色main.yamlnode_exporter_tasks.yml角色触发任务notifyextra_tasks.yml角色prometheus_node_config.j2模板文件 执行命令查看变量 剧本功能 功能1&#xff1a; 批量执行node_ex…

记一次 .NET某工厂报警监控设置 崩溃分析

一&#xff1a;背景 1. 讲故事 前些天有位朋友在微信上丢了一个崩溃的dump给我&#xff0c;让我帮忙看下为什么出现了崩溃&#xff0c;在 Windows 的事件查看器上显示的是经典的 访问违例 &#xff0c;即 c0000005 错误码&#xff0c;不管怎么说有dump就可以上windbg开干了。…

Python图像处理——基于Pytorch框架ResNet152特征提取的MNIST手写数字识别

1. 数据集介绍 MNIST手写数字数据集&#xff1a; http://yann.lecun.com/exdb/mnist/ MNIST 数据集一共有 7 万张图片&#xff0c;其中 6 万张是训练集&#xff0c; 1 万张是测试集。每张图片是 28 28 的 0−9 的手写数字图片组成。每个图片是黑底白字的形式&#xff0c;黑底…

前端技术回顾系列 10|TS 泛型在类和接口中的应用

在微信中阅读,关注公众号:CodeFit。 创作不易,如果你觉得这篇文章对您有帮助,请不要忘了 点赞、分享 和 关注 我的公众号:CodeFit,为我的持续创作提供动力。 上文回顾:约束泛型(Generic Constraints) 上一篇文章我们回顾了 泛型 在 TypeScript 中的高级用法 —— 泛型…

uniapp开发微信小程序预加载分包

微信小程序分包是一种优化小程序项目结构和性能的方式。它允许开发者将小程序代码包拆分成多个子包&#xff0c;在用户需要时动态加载这些子包&#xff0c;从而减少小程序的首次加载时间和主包的体积。&#xff08;总体积不得大于20M&#xff0c;主包&#xff08;共同文件静态资…