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 returnint lastRet = -1; // index of last element returned; -1 if no suchint expectedModCount = modCount;// prevent creating a synthetic constructorItr() {}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();}}@Overridepublic 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 trafficcursor = 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的区别

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

编译原理:语法分析

目录 引言上下文无关文法 CFG: Context-Free Grammar定义推导方法最左推导和最右推导 分析树分析树->抽象语法树常见的上下文无关文法文法设计二义性文法扩展巴科斯范式&#xff1a;EBNF extended Backus Normal Form 文法和语言分类相关术语直接推导推导*推导句型、句子、语…

Kettle 数据抽取工具使用教程:从入门到实战

一、简介 Kettle 是 Pentaho Data Integration (PDI) 的一个组成部分&#xff0c;是一个开源的数据集成工具。它被广泛用于数据的抽取、转换和加载 (ETL) 过程。Kettle 提供了一个易于使用的图形界面&#xff0c;可以轻松设计和执行 ETL 流程。 github 源码地址&#xff1a;ht…

机器学习第四十三周周报 aGNN

文章目录 week43 aGNN摘要Abstract1. 题目2. Abstract3. 网络架构3.1 aGNN3.1.1 输入与输出模块3.1.2 嵌入层3.1.3编码器解码器模块&#xff1a;带有多头注意力层的GCN 3.2 可释性模型&#xff1a;SHAP 4. 文献解读4.1 Introduction4.2 创新点4.3 实验过程4.3.1 实验区域以及场…

Golang免杀-分离式加载器(传参)AES加密

目录 enc.go 生成: dec.go --执行dec.go...--上线 cs生成个c语言的shellcode. enc.go go run .\enc.go shellcode 生成: --key为公钥. --code为AES加密后的数据, ----此脚本每次运行key和code都会变化. package mainimport ("bytes""crypto/aes"&…

Linux - 复盘一次句柄数引发的故障

文章目录 Pre&#xff08;内核、用户、进程&#xff09;句柄数设置问题 shell修复 Pre Linux - 深入理解/proc虚拟文件系统&#xff1a;从基础到高级 &#xff08;内核、用户、进程&#xff09;句柄数设置 在Linux系统中&#xff0c;进程打开的最大句柄数可以通过多种方式配置…

立创·天空星开发板-GD32F407VE-Timer

本文以 立创天空星开发板-GD32F407VET6-青春版 作为学习的板子&#xff0c;记录学习笔记。 立创天空星开发板-GD32F407VE-Timer 定时器基本定时器示例 定时器 定时器是嵌入式系统中常用的一种外设&#xff0c;它可以产生一定的时间间隔、延时、定时等功能&#xff0c;广泛应用于…

如何自动生成数据库的样本数据(以MySQL和SQLynx为例)

目录 1 功能概述 2 主要特点 3 使用场景 4 使用示例 5 结论 SQLynx 是一款领先的 SQL 集成开发环境&#xff08;IDE&#xff09;&#xff0c;其强大的功能得到了全球用户的广泛认可。SQLynx 不仅在数据库管理和 SQL 查询方面表现出色&#xff0c;还提供了一项特别实用的功能…

VMware 三种网络模式

目录 一、网卡、路由器、交换机 二、虚拟网络编辑器 三、网络模式 1.桥接模式 通信方式 特点 配置 连通情况 使用场景 2.NAT模式 通信方式 特点 配置 连通情况 使用场景 3.仅主机 通信方式 特点 配置 连通情况 使用场景 一、网卡、路由器、交换机 网卡(Ne…

visio添加表格

插入Excel表格&#xff1a; 打开Microsoft Visio&#xff0c;新建一个空白画布。点击菜单栏中的“插入”。在插入中点击“图表”。在弹出的插入对象设置页面中选择“Microsoft Excel工作表”。点击确定按钮&#xff0c;然后在表格中输入内容。将鼠标点击到画布的空白处&#x…

OpenCV计算形状之间的相似度ShapeContextDistanceExtractor类的使用

操作系统&#xff1a;ubuntu22.04OpenCV版本&#xff1a;OpenCV4.9IDE:Visual Studio Code编程语言&#xff1a;C11 1.功能描述 ShapeContextDistanceExtractor是OpenCV库中的一个类&#xff0c;主要用于计算形状之间的相似度或距离。它是基于形状上下文&#xff08;Shape Co…

OpenStack云平台管理

OpenStack云平台管理 文章目录 OpenStack云平台管理资源列表基础环境一、部署Openstack二、创建网络和路由2.1、删除默认的网络2.2、创建网络和路由2.2.1、创建外部网络2.2.2、创建内部网络 2.3、创建路由 三、创建实例3.1、配置实例3.2、配置NAT转换 四、绑定浮动IP地址五、添…

C# WinForm —— 34 ToolStrip 工具栏 介绍

1. 简介 工具栏 ToolStrip&#xff0c;一般紧贴在菜单栏下面 2. 属性 属性解释(Name)控件ID&#xff0c;在代码里引用的时候会用到Enabled控件是否启用Dock定义要绑定到容器的控件边框&#xff0c;默认是topAnchor定义某个控件绑定到的容器的边缘。当控件锚定到某个边缘时&a…

分类模型:MATLAB判别分析

1. 判别分析简介 判别分析&#xff08;Discriminant Analysis&#xff09; 是一种统计方法&#xff0c;用于在已知分类的样本中构建分类器&#xff0c;并根据特征变量对未知类别的样本进行分类。常见的判别分析方法包括线性判别分析&#xff08;Linear Discriminant Analysis, …

韩顺平0基础学java——第22天

p441-459 异常exception 选中代码块&#xff0c;快捷键ctraltt6&#xff0c;即trt-catch 如果进行了异常处理&#xff0c;那么即使出现了异常&#xff0c;但是会继续执行 程序过程中发生的异常事件分为两大类&#xff1a; 异常体系图※ 常见的运行异常&#xff1a;类型转换…

EFuse概念解析

EFuse概念解析 EFUSE Key Parameter iNOM 代表的是&#xff0c;Efuse运行时候的电流 tNOM 代表的是&#xff0c;Efuse电流与时间的曲线 INOM通过VOC_Thrs设置 VOC_THRS VOC_THRS/Rsense Vsense采样小于VOC_THRS时候不动作 Vsense采样大于VOC_THRS时候根据Efuse_I2T曲线来…

平时的财经日历会影响黄金现货走势吗?

现货黄金的价格走势会受到诸多因素的影响&#xff0c;比如在财经日历上&#xff0c;美国的非农就业报告、GDP、利率公告、通胀数据等新闻和经济公告&#xff0c;都可能会对市场产生重大影响&#xff0c;尤其是当这些数据与市场预期不符的时候。所以比起单纯地进行技术分析和图表…

【C++ | 移动构造函数】一文了解C++11的 移动构造函数

&#x1f601;博客主页&#x1f601;&#xff1a;&#x1f680;https://blog.csdn.net/wkd_007&#x1f680; &#x1f911;博客内容&#x1f911;&#xff1a;&#x1f36d;嵌入式开发、Linux、C语言、C、数据结构、音视频&#x1f36d; ⏰发布时间⏰&#xff1a;2024-06-12 2…

Linux基础IO【II】真的很详细

目录 一.文件描述符 1.重新理解文件 1.推论 2.证明 2.理解文件描述符 1.文件描述符的分配规则 3.如何理解文件操作的本质&#xff1f; 4.输入重定向和输出重定向 1.原理 2.代码实现重定向 3.dup函数 ​编辑 4.命令行中实现重定向 二.关于缓冲区 1.现象 …

【学习笔记】Linux

Linux 1、 介绍 1.1、概述 1.2、特点 1.3、Linux的发行版2、 基础篇 —— 文件系统 2.1、文件系统 2.2、目录结构3、 基础篇 —— VI/VIM 编辑器 3.1、概述 3.2、编辑器模式及常用命令4、 基础篇 —— 网络配置 4.1、VMware NetWork …

电路笔记 : 嘉立创EDA 导入、查找、设计管理器(快速寻找网络标签)功能+DRC错误检查和处理

导入功能 查找功能 可查找多种类型&#xff0c;如原件名称、网络标签等 设计管理器 图层查看 DRC错误 规则设置 线距问题 大多数PCB制造商能够可靠地生产5 mil间距的走线和间隙。这是一个常见的标准&#xff0c;适合大多数消费级和工业级电子产品。在5 mil以上的间距&#xff…