List之ArrayList、LinkedList深入分析

集合

Java 集合, 也叫作容器,主要是由两大接口派生而来:一个是 Collection接口,主要用于存放单一元素;另一个是 Map 接口,主要用于存放键值对。对于Collection 接口,下面又有三个主要的子接口:ListSetQueue

Java 集合框架如下图所示:

Java 集合框架概览

Collection接口

概念:对象的容器,定义了对多个对象进项操作的的常用方法。可实现数组的功能。
与数组的区别:数组长度固定,集合长度不固定;数组可以存储基本类型和引用类型,集合只能存储引用类型
位置: java.util.*

接口中的方法

boolean add(Object obj) //添加一个对象。
boolean addAll(Collection c) //讲一个集合中的所有对象添加到此集合中。
void clear() //清空此集合中的所有对象。
boolean contains(Object o) //检查此集合中是否包含o对象。
boolean equals(Object o) //比较此集合是否与指定对象相等。
boolean isEmpty() //判断此集合是否为空。
boolean remove(Object o) //在此集合中移除o对象。
int size() //返回此集合中的元素个数。
Object[] toArray() //将此集合转换成数组。
/*** Collection接口的使用(一)* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断*/
public class Demo1{pubic static void main(String[] args){//创建集合Collection collection = new ArrayList();        
//      * 1.添加元素Collection.add("苹果");Collection.add("西瓜");Collection.add("榴莲");System.out.println("元素个数:"+collection.size());System.out.println(collection);
//      * 2.删除元素collection.remove("榴莲");System.out.println("删除之后:"+collection.size());
//      * 3.遍历元素//3.1 使用增强for for(Object object : collection){System.out.println(object);}//3.2 使用迭代器(迭代器专门用来遍历集合的一种方式)//hasnext();判断是否有下一个元素//next();获取下一个元素//remove();删除当前元素Iterator iterator=collection.Itertor();while(iterator.hasnext()){String object=(String)iterator.next();System.out.println(s);//删除操作//collection.remove(s);引发错误:并发修改异常//iterator.remove();应使用迭代器的方法
//      * 4.判断System.out.println(collection.contains("西瓜"));//trueSystem.out.println(collection.isEmpty());//false}}
}

Collection子接口

List集合

特点:有序、有下标、元素可以重复

/*** List子接口的使用(一)* 特点:1.有序有下标 2.可以重复* * 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断* 5.获取位置*/
public class Demo3 {public static void main(String[] args) {List list=new ArrayList<>();//1.添加元素list.add("tang");list.add("he");list.add(0,"yu");//插入操作System.out.println("元素个数:"+list.size());System.out.println(list.toString());//2.删除元素list.remove(0);//list.remove("yu");结果同上System.out.println("删除之后:"+list.size());System.out.println(list.toString());//3.遍历元素//3.1 使用for遍历for(int i=0;i<list.size();++i) {System.out.println(list.get(i));}//3.2 使用增强forfor(Object object:list) {System.out.println(object);}//3.3 使用迭代器Iterator iterator=list.iterator();while (iterator.hasNext()) {System.out.println(iterator.next());}//3.4使用列表迭代器,listIterator可以双向遍历,添加、删除及修改元素。ListIterator listIterator=list.listIterator();//从前往后while (listIterator.hasNext()) {System.out.println(listIterator.next());		}//从后往前(此时“遍历指针”已经指向末尾)while(listIterator.hasPrevious()) {System.out.println(listIterator.previous());}//4.判断System.out.println(list.isEmpty());System.out.println(list.contains("tang"));//5.获取位置System.out.println(list.indexOf("tang"));}
}
/*** List子接口的使用(二)* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断* 5.获取位置*/
public class Demo4 {public static void main(String[] args) {List list=new ArrayList();//1.添加数字数据(自动装箱)list.add(20);list.add(30);list.add(40);list.add(50);System.out.println("元素个数:"+list.size());System.out.println(list.toString());//2.删除元素list.remove(0);//list.remove(20);很明显数组越界错误,改成如下//list.remove(Object(20));//list.remove(new Integer(20));System.out.println("元素个数:"+list.size());System.out.println(list.toString());//3-5不再演示,与之前类似//6.补充方法subList,返回子集合,含头不含尾List list2=list.subList(1, 3);//[1,3)System.out.println(list2.toString());	}
}
ArrayList【重点】

ArrayList是List接口的实现类,也是开发当中最常用的集合类

  • 数组结构实现,查询快、增删慢;
  • JDK1.2版本,运行效率快、线程不安全。
/*** ArrayList的使用* 存储结构:数组;* 特点:查找遍历速度快,增删慢。* 1.添加元素* 2.删除元素* 3.遍历元素* 4.判断* 5.查找*/
public class Demo5 {public static void main(String[] args) {ArrayList arrayList=new ArrayList<>();//1.添加元素Student s1=new Student("唐", 21);Student s2=new Student("何", 22);Student s3=new Student("余", 21);arrayList.add(s1);arrayList.add(s2);arrayList.add(s3);System.out.println("元素个数:"+arrayList.size());System.out.println(arrayList.toString());//2.删除元素arrayList.remove(s1);//arrayList.remove(new Student("唐", 21));//注:这样可以删除吗(不可以)?显然这是两个不同的对象。//假如两个对象属性相同便认为其是同一对象,那么如何修改代码?//romove的底层是调用对象的equals方法//所以想对象属性相同就修改,就必须修改对象的equals方法//        若一定要写包含任何类型的集合,可以这样写,Object就是包含任何类
//        ArrayList<Object> list1=new ArrayList<>();//        1.获取某个索引位置处的元素值get(index)String e=list.get(4);System.out.println(e);//        2.获取集合的大小size()System.out.println(list.size());//        3.完成遍历for(int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}//        4.删除某个索引位置的元素值,并返回被删除的元素值remove(index)System.out.println(list);String e2=list.remove(1);System.out.println("e2=" + e2);System.out.println(list);//        5.直接删除元素值,remove(value) 删除成功返回true,删除失败返回false,如果存在多个相同的元素,只会删除第一次出现的目标元素System.out.println(list.remove("hwq"));System.out.println(list);//        6.修改某个索引位置处的元素值,并会返回被修改的元素 set(index,element(要修改的值))String name=list.set(0,"牛");System.out.println(name);System.out.println(list);//        7.contains:查找元素是否存在System.out.println(list.contains("牛"));//        8.clear 清空集合list.clear();//        9.isEmpty 判断是否为空System.out.println(list.isEmpty());//        10.addAll:添加多个元素ArrayList list1 = new ArrayList();list1.add("红雷梦");list1.add("三国");list.addAll(list1);System.out.println(list);//        11.containsAll 查找多个元素System.out.println(list.containsAll(list1));//        12.removeAll:删除多个元素list.removeAll(list1);System.out.println(list);}
}
ArrayList源码分析【重点】

ArrayList 是Java集合框架中常用的动态数组实现,它提供了动态增长的能力,允许在数组尾部进行快速的随机访问。下面我们将对 ArrayList 的源码进行分析,深入了解其实现原理和关键方法。

1. 类声明和继承关系
public class ArrayList<E> extends AbstractList<E>implements List<E>, RandomAccess, Cloneable, java.io.Serializable {// ...
}
  • ArrayList 类继承自 AbstractList,实现了 List 接口,同时还实现了 RandomAccess(随机访问标记接口)、Cloneable(可克隆接口)、Serializable(可序列化接口)。
2. 成员变量
transient Object[] elementData;
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
private static final int DEFAULT_CAPACITY = 10;
private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
  • elementData:存储元素的数组。
  • DEFAULTCAPACITY_EMPTY_ELEMENTDATA:空数组,用于延迟数组的初始化。
  • DEFAULT_CAPACITY:默认初始容量。
  • MAX_ARRAY_SIZE:数组的最大容量。
3. 构造方法
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}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(Collection<? extends E> c) {elementData = c.toArray();if ((size = elementData.length) != 0) {if (elementData.getClass() != Object[].class)elementData = Arrays.copyOf(elementData, size, Object[].class);} else {this.elementData = EMPTY_ELEMENTDATA;}
}
  • ArrayList 提供了多个构造方法,包括默认构造方法、指定初始容量的构造方法以及接收 Collection 的构造方法。
  • 在默认构造方法中,使用了延迟加载的技术,初始时 elementDataDEFAULTCAPACITY_EMPTY_ELEMENTDATA也就是空数组这点非常重要‼️,只有在第一次add添加元素时才会初始化为默认容量(10)的数组。
4. 核心方法
4.1 add 方法
public boolean add(E e) {ensureCapacityInternal(size + 1);elementData[size++] = e;return true;
}private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;
}private void ensureExplicitCapacity(int minCapacity) {modCount++;if (minCapacity - elementData.length > 0)grow(minCapacity);
}private void grow(int minCapacity) {// overflow-conscious codeint 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);
}
  • add 方法:添加元素,确保容量足够,如果需要,进行数组扩容。
  • ensureCapacityInternal 方法:确保容量足够的内部方法,负责调用 ensureExplicitCapacity 进行实际的扩容操作。
  • calculateCapacity 方法:计算容量的方法,处理空数组的情况。
  • grow 方法:数组扩容的核心方法,通过 Arrays.copyOf 进行扩容,新容量为原容量的1.5倍。
理解过程
//这是一个空的数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

这段源码说明当你没有向集合中添加任何元素时,集合容量为0。那么默认的10个容量怎么来的呢?

这就得看看add方法的源码了:

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

假设你new了一个数组,当前容量为0,size当然也为0。这时调用add方法进入到ensureCapacityInternal(size + 1);该方法源码如下:

private void ensureCapacityInternal(int minCapacity) {ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}

该方法中的参数minCapacity传入的值为size+1也就是 1,接着我们再进入到calculateCapacity(elementData, minCapacity)里面:

private static int calculateCapacity(Object[] elementData, int minCapacity) {if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {return Math.max(DEFAULT_CAPACITY, minCapacity);}return minCapacity;
}

上文说过,elementData就是存放元素的数组,当前容量为0,if条件成立,返回默认容量DEFAULT_CAPACITY也就是10。这个值作为参数又传入ensureExplicitCapacity()方法中,进入该方法查看源码:

private void ensureExplicitCapacity(int minCapacity) {modCount++;// overflow-conscious codeif (minCapacity - elementData.length > 0) // 当需要的空间大于现在数组的容量就要考虑扩容grow(minCapacity); //数组扩容
}

我们先不要管modCount这个变量。

因为elementData数组长度为0,所以if条件成立,调用grow方法,重要的部分来了,我们再次进入到grow方法的源码中:

private void grow(int minCapacity) {// overflow-conscious codeint oldCapacity = elementData.length; // 现在数组的容量0int newCapacity = oldCapacity + (oldCapacity >> 1); // 新数组的容量0if (newCapacity - minCapacity < 0) // 成立newCapacity = minCapacity;//newCapacity = 10if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);// minCapacity is usually close to size, so this is a win:elementData = Arrays.copyOf(elementData, newCapacity);
}

这个方法先声明了一个oldCapacity变量将数组长度赋给它,其值为0;又声明了一个newCapacity变量其值为oldCapacity+一个增量,可以发现这个增量是和原数组长度有关的量,当然在这里也为0。第一个if条件满足,newCapacity的值为10(这就是默认的容量,不理解的话再看看前面)。第二个if条件不成立,也可以不用注意,因为MAX_ARRAY_SIZE的定义如下:

private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

这个值太大了以至于第二个if条件没有了解的必要。

最后一句话就是为elementData数组赋予了新的长度,Arrays.copyOf()方法返回的数组是新的数组对象,原数组对象不会改变,该拷贝不会影响原来的数组。copyOf()的第二个自变量指定要建立的新数组长度,如果新数组的长度超过原数组的长度,则保留数组默认值。

这时候再回到add的方法中,接着就向下执行elementData[size++] = e;到这里为止关于ArrayList就讲解得差不多了,当数组长度为10的时候你们可以试着过一下源码,查一下每次的增量是多少(答案是每次扩容为原来的1.5倍

总结

  1. 存储元素的结构是Object[]数字,具体的Object由new ArrayList();的T决定

  2. 没有给定初始容量,默认初始容量为10,当添加元素后才初始化为10

  3. 达到额定容量,每次扩容为原来的1.5倍,比如初始容量为10,当添加第11个元素的时候,发现容量不足了,就会调用grow方法进行扩容,扩容后容量为(10 + 10 / 2) = 15 ,如果初始容量为33,则扩容后的容量为(33 + 33 / 2) = 49,会舍弃小数部分,因为底层使用了位运算 >> 1

Vector

Vector在实际开发中使用较少,为了保证线程安全,很多方法使用了synchronized而牺牲了性能,大部分源码和ArrayList相同,这里就不深入介绍了

在这里插入图片描述

  • 数组结构实现,查询快、增删慢;
  • JDK1.0版本,运行效率慢、线程安全。
/*** Vector的演示使用* *1.添加数据*2.删除数据*3.遍历*4.判断*/
public class Demo1 {public static void main(String[] args) {Vector vector=new Vector<>();//1.添加数据vector.add("tang");vector.add("he");vector.add("yu");System.out.println("元素个数:"+vector.size());//2.删除数据/** vector.remove(0); vector.remove("tang");*///3.遍历//使用枚举器Enumeration enumeration=vector.elements();while (enumeration.hasMoreElements()) {String s = (String) enumeration.nextElement();System.out.println(s);}//4.判断System.out.println(vector.isEmpty());System.out.println(vector.contains("he"));//5. Vector其他方法//firstElement()  lastElement()  ElementAt();}
}
LinkedList
  • 特点:链表结构实现,增删快,查询慢
/*** LinkedList的用法* 存储结构:双向链表* 1.添加元素* 2.删除元素* 3.遍历* 4.判断*/
public class Demo2 {public static void main(String[] args) {LinkedList linkedList=new LinkedList<>();Student s1=new Student("唐", 21);Student s2=new Student("何", 22);Student s3=new Student("余", 21);//1.添加元素linkedList.add(s1);linkedList.add(s2);linkedList.add(s3);linkedList.add(s3);System.out.println("元素个数:"+linkedList.size());System.out.println(linkedList.toString());//2.删除元素/** linkedList.remove(new Student("唐", 21));* System.out.println(linkedList.toString());*///3.遍历//3.1 使用forfor(int i=0;i<linkedList.size();++i) {System.out.println(linkedList.get(i));}//3.2 使用增强forfor(Object object:linkedList) {Student student=(Student) object;System.out.println(student.toString());}//3.3 使用迭代器Iterator iterator =linkedList.iterator();while (iterator.hasNext()) {Student student = (Student) iterator.next();System.out.println(student.toString());}//3.4 使用列表迭代器(略)//4. 判断System.out.println(linkedList.contains(s1));System.out.println(linkedList.isEmpty());System.out.println(linkedList.indexOf(s3));}
}
LinkedList源码分析

LinkedList首先有三个属性:

  • 链表大小:transient int size = 0;
  • (指向)第一个结点/头结点:transient Node<E> first;
  • (指向)最后一个结点/尾结点:transient Node<E> last;

关于Node类型我们再进入到类里看看:

private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}
}

首先item存放的是实际数据;next指向下一个结点而prev指向上一个结点。

Node带参构造方法的三个参数分别是前一个结点、存储的数据、后一个结点,调用这个构造方法时将它们赋值给当前对象。

LinkedList是如何添加元素的呢?先看看add方法:

public boolean add(E e) {linkLast(e);return true;
}

进入到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;elsel.next = newNode;size++;modCount++;
}

假设刚开始new了一个LinkedList对象,first和last属性都为空,调用add进入到linkLast方法。

首先创建一个Node变量 l 将last(此时为空)赋给它,然后new一个newNode变量存储数据,并且它的前驱指向l,后继指向null;再把last指向newNode。如下图所示:

img

如果满足if条件,说明这是添加的第一个结点,将first指向newNode:

img

至此,LinkedList对象的第一个数据添加完毕。假设需要再添加一个数据,我们可以再来走一遍,过程同上不再赘述,图示如下:

img

ArrayList和LinkedList区别
  • ArrayList:必须开辟连续空间,查询快,增删慢。
  • LinkedList:无需开辟连续空间,查询慢,增删快。

img

总结

在不能提前确定容器大小的情况下可以使用List接口实现的集合类,ArrayList适合频繁查询、修改的场景,不适合频繁增删的场景;而LinkedList则相反

如果觉得本篇文章对你有帮助,可否点个小赞😺;篇幅较长建议收藏🫠;关注一手等待后续更新更多干货🚀

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

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

相关文章

洗衣洗鞋店小程序对接水洗唛打印,一键预约,支付无忧

随着社会的进步和科技的发展&#xff0c;我们的生活幸福感与日俱增。为了让我们从琐碎中解脱出来&#xff0c;干洗店洗鞋店行业也日新月异。今天&#xff0c;我为大家推荐这款优秀的干洗店小程序系统&#xff0c;让您的洗衣洗鞋服务体验更上一层楼。 干洗店管理系统是一款专为洗…

阿里云和腾讯云区别价格表,云服务器费用对比2024年最新

2024年阿里云服务器和腾讯云服务器价格战已经打响&#xff0c;阿里云服务器优惠61元一年起&#xff0c;腾讯云服务器61元一年&#xff0c;2核2G3M、2核4G、4核8G、4核16G、8核16G、16核32G、16核64G等配置价格对比&#xff0c;阿腾云atengyun.com整理阿里云和腾讯云服务器详细配…

力扣热题100_普通数组_73_矩阵置零

文章目录 题目链接解题思路解题代码 题目链接 73.矩阵置零 给定一个 m x n 的矩阵&#xff0c;如果一个元素为 0 &#xff0c;则将其所在行和列的所有元素都设为 0 。请使用 原地 算法。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,1,1],[1,0,1],[1,1,1]] 输出&…

lvs集群介绍

目录 一、LVS集群基本介绍 1、什么是集群 2、集群的类型 2.1 负载均衡群集&#xff08;Load Balance Cluster) 2.2 高可用群集(High Availiablity Cluster) 2.3 高性能运算群集(High Performance Computing Cluster) 3、负载均衡集群的结构 ​编辑 4、LVS集群类型中的…

3D资产管理

3D 资产管理是指组织、跟踪、优化和分发 3D 模型和资产以用于游戏、电影、AR/VR 体验等各种应用的过程。 3D资产管理也称为3D内容管理。 随着游戏、电影、建筑、工程等行业中 3D 内容的增长&#xff0c;实施有效的资产管理工作流程对于提高生产力、减少错误、简化工作流程以及使…

足球俱乐部管理系统:Java与SpringBoot的管理系统实践

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

MySQL存储函数

存储函数是有返回值存储过程&#xff0c;存储函数的参数只能还是IN类型的 1、语法 create function 存储函数名称 &#xff08;[参数列表]&#xff09;Returns type [characterrastic...]Begin--SQL语句Return ..;End;characterrastic说明&#xff1a;Deterministic:相同的输…

uniapp使用openlayers加载地图服务

uniapp使用openlayers加载地图服务 <!-- 地图组件 --> <template><view id"myMap" :regionChangeItem"regionChangeItem" :change:regionChangeItem"olRender.selectAdministrativeRegion":tagSelectProducetagSelectProduce :t…

Visual Studio 2022之Release版本程序发送到其它计算机运行

目录 1、缺少dll​ 2、应用程序无法正常启动 3、This application failed to start because no Qt platform plugin could be initialized. 代码在Debug模式下正常运行&#xff0c;然后切换到Release模式下&#xff0c;也正常运行&#xff0c;把第三方平台的dll拷贝到exe所在…

IPv6扩展头(四)——分片头

分片头部&#xff08;Fragment Header&#xff09;用于IPv6源节点向目的节点发送一个大于路径MTU的数据报。 一、优势 IPv6 分片头具有多种优势&#xff0c;可提高网络效率&#xff0c;包括减少数据包延迟和减少网络拥塞。使用 IPv6 分片头&#xff0c;数据包在源处而不是中间…

Uninty 鼠标点击(摄像机发出射线-检测位置)

平面来触发碰撞&#xff0c;胶囊用红色材质方便观察。 脚本挂载到胶囊上方便操作。 目前实现的功能&#xff0c;鼠标左键点击&#xff0c;胶囊就移动到那个位置上。 using System.Collections; using System.Collections.Generic; using UnityEngine;public class c6 : MonoBe…

数据结构-线段树

&#x1f4d1;前言 本文主要是【线段树】——线段树简单使用的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&…

PyCharm Community Edition 2023.3.3,UI界面设置成旧版

File->Settings->Appearance & Behavior->New UI->Enable new UI(取消勾选)->重启PyCharm 旧版UI: 新版UI&#xff1a;

对 JVM 的类加载机制以及寻找字节码文件的“双亲委派模型”的理解

目录 1、JVM 的类加载机制 1.1、加载 1.2、验证 1.3、准备 1.4、解析 1.5、初始化 2、双亲委派模型 2.1、工作过程 1、JVM 的类加载机制 类加载指的是 Java 进程运行的时候&#xff0c;需要把 .class 文件从硬盘读取到内存&#xff0c;并进行一系列的校验解析的过程。…

人民日报:用好“人工智能+” 赋能产业升级

以下文章来源&#xff1a;北京日报 文生视频、智能家居、智慧工厂……近年来&#xff0c;人工智能发展速度之快、应用范围之广备受瞩目。 政府工作报告提出&#xff0c;深化大数据、人工智能等研发应用&#xff0c;开展“人工智能”行动&#xff0c;打造具有国际竞争力的数字产…

力扣589、590、102、107、429、199、637、515、116、117、104、111、226、101-Java刷题笔记

一、589. N 叉树的前序遍历 - 力扣&#xff08;LeetCode&#xff09; 1.1题目 给定一个 n 叉树的根节点 root &#xff0c;返回 其节点值的 前序遍历 。 n 叉树 在输入中按层序遍历进行序列化表示&#xff0c;每组子节点由空值 null 分隔&#xff08;请参见示例&#xff09…

使用Python制作自己的wheel文件

平时自己利用Python制作一个个小工具后想分享给别人&#xff0c;但又嫌分享一堆项目代码很麻烦&#xff0c;那么你可以考虑将自己的项目打包成一个wheel文件&#xff0c;别人拿到文件后只需pip install安装即可使用&#xff0c;非常方便。 在上一篇博文中&#xff0c;利用nvid…

在maven多模块之间调用报错

错误信息为&#xff1a;不能解决maven_02_ssm项目的依赖问题&#xff0c;找不到maven_03_pojo这个jar包。 为什么找不到呢? 原因是Maven会从本地仓库找对应的jar包&#xff0c;但是本地仓库又不存在该jar包所以会报错。 在IDEA中是有maven_03_pojo这个项目&#xff0c;所以…

使用 Python 字典向 SQLite 插入数据

将Python字典数据插入SQLite数据库中其实有很多好处&#xff0c;例如使用字典的结构可以简化插入数据的代码&#xff0c;使其更加紧凑和易于理解。这降低了代码的复杂性&#xff0c;并使代码更易于维护。那么在我们日常使用中会有哪些问题呢&#xff1f;一起看看我是如何解决的…

华为配置DHCP Snooping防止DHCP Server仿冒者攻击示例

配置DHCP Snooping防止DHCP Server仿冒者攻击示例 组网图形 图1 配置DHCP Snooping防止DHCP Server仿冒者攻击组网图 DHCP Snooping简介配置注意事项组网需求配置思路操作步骤配置文件 DHCP Snooping简介 在一次DHCP客户端动态获取IP地址的过程中&#xff0c;DHCP Snoopi…