JDK源码解析-ArrayList

news2024/12/26 21:48:04

1. ArrayList类

1.1 ArrayList类结构图

ArrayList 是一个用数组实现的集合,支持随机访问,元素有序且可以重复。

(1)ArrayList 是一种变长的集合类,基于定长数组实现。

(2)ArrayList 允许空值和重复元素,当往 ArrayList 中添加的元素数量大于其底层数组容量时,其会通过扩容机制重新生成一个更大的数组。

(3)ArrayList 底层基于数组实现,所以其可以保证在 O(1) 复杂度下完成随机查找操作。

(4)ArrayList 是非线程安全类,并发环境下,多个线程同时操作 ArrayList,会引发不可预知的异常或错误。

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

'xxs'

①、实现 RandomAccess 接口

这是一个标记接口,一般此标记接口用于 List实现,以表明它们支持快速(通常是恒定时间)的随机访问

②、实现 Cloneable 接口

Cloneable 和 RandomAccess 接口一样也是一个标记接口,接口内无任何方法体和常量的声明,也就是说如果想克隆对象,必须要 实现 Cloneable 接口,表明该类是可以被克隆的。

③、实现 Serializable 接口

标记接口,表示能被序列化

④、实现 List 接口

这个接口是 List 类集合的上层接口,定义了实现该接口的类都必须要实现的一组方法

'xxs'

1.2 字段属性

 //集合的默认大小
 private static final int DEFAULT_CAPACITY = 10;
 //空的数组实例
 private static final Object[] EMPTY_ELEMENTDATA = {};
 //这也是一个空的数组实例,和EMPTY_ELEMENTDATA空数组相比是用于了解添加元素时数组膨胀多少
 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
 //存储 ArrayList集合的元素,集合的长度即这个数组的长度
 //1、当 elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA 时将会清空 ArrayList
 //2、当添加第一个元素时,elementData 长度会扩展为 DEFAULT_CAPACITY=10
 transient Object[] elementData;
 //表示集合的长度
 private int size;

1.3 类构造器

1. 无参构造:

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

此无参构造函数将创建一个 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 声明的数组,注意此时初始容量是0,而不是大家以为的 10。

注意:根据默认构造函数创建的集合,ArrayList list = new ArrayList();此时集合长度是0.

2. 重载:有参构造ArrayList(int initialCapacity)

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 集合。当大于0时,给定多少那就创建多大的数组;当等于0时,创建一个空数组;当小于0时,抛出异常。

3.重载: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;
    }
}

将已有的集合复制到 ArrayList 集合中

思考:无参构造和0长度构造有什么区别?

//两种方式构建list,有什么区别?
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList(0);
@Test
public void test2(){
    //两种方式构建list,有什么区别?
    ArrayList list1 = new ArrayList();
    ArrayList list2 = new ArrayList(0);

    //打印对象头
    System.out.println(ClassLayout.parseInstance(list1).toPrintable());
    System.out.println(ClassLayout.parseInstance(list2).toPrintable());

    System.out.println("========");

    //add一个元素之后再来打印试试
    list1.add(1);
    list2.add(1);

    System.out.println(ClassLayout.parseInstance(list1).toPrintable());
    System.out.println(ClassLayout.parseInstance(list2).toPrintable());
}

'xxs'

原理:

//calculateCapacity
//每次元素变动,比如add,会调用该函数判断容量情况
private static int calculateCapacity(Object[] elementData, int minCapacity) {
	//定义default empty数组的意义就在这里!用于扩容时判断当初采用的是哪种构造函数
	if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
	    //如果是无参的构造函数,用的就是该default empty
	    //那么第一次add时候,容量取default和min中较大者
	    return Math.max(DEFAULT_CAPACITY, minCapacity);
	}
	//如果是另外两个构造函数,比如指定容量为5,或者初始参数collection为5
	//那就直接返回5,一定程度上,节约了内存空间
	return minCapacity;
}

1.4 添加元素

// 思考:List集合底层是数组,为什么能添加到任意多个元素?
list1.add(1);

源码:

public boolean add(E e) {
   ensureCapacityInternal(size + 1);  //添加元素之前,首先要确定集合的大小(是否需要扩容)
   elementData[size++] = e;
   return true;
}

如上所示,在通过调用 add 方法添加元素之前,要首先调用 ensureCapacityInternal 方法来确定集合的大小,如果集合满了,则要进行扩容操作。

private void ensureCapacityInternal(int minCapacity) {//这里的minCapacity 是集合当前大小+1
    //elementData 是实际用来存储元素的数组,注意数组的大小和集合的大小不是相等的,前面的size是指集合大小
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//如果数组为空,则从size+1的值和默认值10中取最大的
        return Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    return minCapacity;//不为空,则返回size+1
}
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}

在 ensureExplicitCapacity 方法中,首先对修改次数modCount加一,这里的modCount给ArrayList的迭代器使用的,在并发操作被修改时,提供快速失败行为(保证modCount在迭代期间不变,否则抛出ConcurrentModificationException异常,可以查看源码865行),接着判断minCapacity是否大于当前ArrayList内部数组长度,大于的话调用grow方法对内部数组elementData扩容,grow方法代码如下:

private void grow(int minCapacity) {
    int oldCapacity = elementData.length;//得到原始数组的长度
    int newCapacity = oldCapacity + (oldCapacity >> 1);//新数组的长度等于原数组长度的1.5倍
    if (newCapacity - minCapacity < 0)//当新数组长度仍然比minCapacity小,则为保证最小长度,新数组等于minCapacity
        newCapacity = minCapacity;
    //MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8 = 2147483639
    if (newCapacity - MAX_ARRAY_SIZE > 0)//当得到的新数组长度比 MAX_ARRAY_SIZE 大时,调用 hugeCapacity 处理大数组
        newCapacity = hugeCapacity(minCapacity);
    //调用 Arrays.copyOf 将原数组拷贝到一个大小为newCapacity的新数组(注意是拷贝引用)
    elementData = Arrays.copyOf(elementData, newCapacity);
}

private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) //
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ? //minCapacity > MAX_ARRAY_SIZE,则新数组大小为Integer.MAX_VALUE
        Integer.MAX_VALUE :
        MAX_ARRAY_SIZE;
}

扩容的核心方法就是调用前面讲过的Arrays.copyOf 方法,创建一个更大的数组,然后将原数组元素拷贝过去即可

对于 ArrayList 集合添加元素,总结一下:

①、当通过 ArrayList() 构造一个空集合,初始长度是为0的,第 1 次添加元素,会创建一个长度为10的数组,并将该元素赋值到数组的第一个位置。

②、第 2 次添加元素,集合不为空,而且由于集合的长度size+1是小于数组的长度10,所以直接添加元素到数组的第二个位置,不用扩容。

③、第 11 次添加元素,此时 size+1 = 11,而数组长度是10,这时候创建一个长度为10+10*0.5 = 15 的数组(扩容1.5倍),然后将原数组元素引用拷贝到新数组。并将第 11 次添加的元素赋值到新数组下标为10的位置。

④、第 Integer.MAX_VALUE - 8 = 2147483639,然后 2147483639%1.5=1431655759(这个数是要进行扩容) 次添加元素,为了防止溢出,此时会直接创建一个 1431655759+1 大小的数组,这样一直,每次添加一个元素,都只扩大一个范围。

⑤、第 Integer.MAX_VALUE - 7 次添加元素时,创建一个大小为 Integer.MAX_VALUE 的数组,在进行元素添加。

⑥、第 Integer.MAX_VALUE + 1 次添加元素时,抛出 OutOfMemoryError 异常。

注意:能向集合中添加 null 的,因为数组可以有 null 值存在。

Object[] obj = {null,1};

ArrayList list = new ArrayList();
list.add(null);
list.add(1);
System.out.println(list.size());//2

1.5 删除元素

public E remove(int index) {
    rangeCheck(index);//判断给定索引的范围,超过集合大小则抛出异常

    modCount++;
    E oldValue = elementData(index);//得到索引处的删除元素

    int numMoved = size - index - 1;
    if (numMoved > 0)//size-index-1 > 0 表示 0<= index < (size-1),即索引不是最后一个元素
        //通过 System.arraycopy()将数组elementData 的下标index+1之后长度为 numMoved的元素拷贝到从index开始的位置
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; //将数组最后一个元素置为 null,便于垃圾回收

    return oldValue;
}

remove(int index) 方法表示删除索引index处的元素,首先通过 rangeCheck(index) 方法判断给定索引的范围,超过集合大小则抛出异常;接着通过 System.arraycopy 方法对数组进行自身拷贝

'xxs'

附:

/*
* src:源数组
  srcPos:源数组要复制的起始位置
  dest:目的数组
  destPos:目的数组放置的起始位置
  length:复制的长度
  注意:src 和 dest都必须是同类型或者可以进行转换类型的数组。
*/
public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);

1.6 修改元素

通过调用 set(int index, E element) 方法在指定索引 index 处的元素替换为 element。并返回原数组的元素。

public E set(int index, E element) {
    rangeCheck(index);//判断索引合法性

    E oldValue = elementData(index);//获得原数组指定索引的元素
    elementData[index] = element;//将指定所引处的元素替换为 element
    return oldValue;//返回原数组索引元素
}

通过调用 rangeCheck(index) 来检查索引合法性

 private void rangeCheck(int index) {
     if (index >= size)
         throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
 }

当索引为负数时,会抛出 java.lang.ArrayIndexOutOfBoundsException 异常。当索引大于集合长度时,会抛出 IndexOutOfBoundsException 异常。

1.7 查找元素

public E get(int index) {
    rangeCheck(index);

    return elementData(index);
}

同理,首先还是判断给定索引的合理性,然后直接返回处于该下标位置的数组元素。

1.8 遍历集合

①、普通 for 循环遍历

前面介绍查找元素时,知道可以通过get(int index)方法,根据索引查找元素,那么遍历同理:

ArrayList list = new ArrayList();
list.add("a");
list.add("b");
list.add("c");
for(int i = 0 ; i < list.size() ; i++){
    System.out.print(list.get(i)+" ");
}

②、迭代器 iterator

ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
Iterator<String> it = list.iterator();
while(it.hasNext()){
    String str = it.next();
    System.out.print(str+" ");
}

在介绍 ArrayList 时,知道该类实现了 List 接口,而 List 接口又继承了 Collection 接口,Collection 接口又继承了 Iterable 接口,该接口有个 Iterator iterator() 方法,能获取 Iterator 对象,能用该对象进行集合遍历,为什么能用该对象进行集合遍历?再看看 ArrayList 类中的该方法实现:

public Iterator<E> iterator() {
    return new Itr();
}

该方法是返回一个 Itr 对象,这个类是 ArrayList 的内部类。

private class Itr implements Iterator<E> {
  int cursor;       //游标, 下一个要返回的元素的索引
  int lastRet = -1; // 返回最后一个元素的索引; 如果没有这样的话返回-1.
  int expectedModCount = modCount;

  //通过 cursor != size 判断是否还有下一个元素
  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];//返回索引为i处的元素,并将 lastRet赋值为i
  }

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

      try {
          ArrayList.this.remove(lastRet);//调用ArrayList的remove方法删除元素
          cursor = lastRet;//游标指向删除元素的位置,本来是lastRet+1的,这里删除一个元素,然后游标就不变了
          lastRet = -1;//lastRet恢复默认值-1
          expectedModCount = modCount;//expectedModCount值和modCount同步,因为进行add和remove操作,modCount会加1
      } catch (IndexOutOfBoundsException ex) {
          throw new ConcurrentModificationException();
      }
  }

  @Override
  @SuppressWarnings("unchecked")
  public void forEachRemaining(Consumer<? super E> consumer) {//便于进行forEach循环
      Objects.requireNonNull(consumer);
      final int size = ArrayList.this.size;
      int i = cursor;
      if (i >= size) {
          return;
      }
      final Object[] elementData = ArrayList.this.elementData;
      if (i >= elementData.length) {
          throw new ConcurrentModificationException();
      }
      while (i != size && modCount == expectedModCount) {
          consumer.accept((E) elementData[i++]);
      }
      // update once at end of iteration to reduce heap write traffic
      cursor = i;
      lastRet = i - 1;
      checkForComodification();
  }

  //前面在新增元素add() 和 删除元素 remove() 时,可以看到 modCount++。修改set() 是没有的
  //也就是说不能在迭代器进行元素迭代时进行增加和删除操作,否则抛出异常
  final void checkForComodification() {
      if (modCount != expectedModCount)
          throw new ConcurrentModificationException();
  }
}

注意在进行 next() 方法调用的时候,会进行 checkForComodification() 调用,该方法表示迭代器进行元素迭代时,如果同时进行增加和删除操作,会抛出 ConcurrentModificationException 异常。比如:

ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
Iterator<String> it = list.iterator();
while(it.hasNext()){
    String str = it.next();
    System.out.print(str+" ");
    list.remove(str);//集合遍历时进行删除或者新增操作,都会抛出 ConcurrentModificationException 异常
    //list.add(str);
    list.set(0, str);//修改操作不会造成异常
}

'xxs'

解决办法是不调用 ArrayList.remove() 方法,转而调用 迭代器的 remove() 方法:

Iterator<String> it = list.iterator();
while(it.hasNext()){
    String str = it.next();
    System.out.print(str+" ");
    //list.remove(str);//集合遍历时进行删除或者新增操作,都会抛出 ConcurrentModificationException 异常
    it.remove();
}

注意:迭代器只能向后遍历,不能向前遍历,能够删除元素,但是不能新增元素。

③、迭代器的变种 forEach

ArrayList<String> list = new ArrayList<>();
 list.add("a");
 list.add("b");
 list.add("c");
for(String str : list){
    System.out.print(str + " ");
}

这种语法可以看成是 JDK 的一种语法糖,通过反编译 class 文件,可以看到生成的 java 文件,其具体实现还是通过调用 Iterator 迭代器进行遍历的。如下:

ArrayList list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("c");
        String str;
        for (Iterator iterator1 = list.iterator(); iterator1.hasNext(); System.out.print((new StringBuilder(String.valueOf(str))).append(" ").toString()))
            str = (String)iterator1.next();

总结:

  • arrayList可以存放null。
  • arrayList本质上就是一个elementData数组。
  • arrayList区别于数组的地方在于能够自动扩展大小,其中关键的方法就是gorw()方法。
  • arrayList由于本质是数组,所以它在数据的查询方面会很快,而在插入删除这些方面,性能下降很多,有移动很多数据才能达到应有的效果

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

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

相关文章

[Android 四大组件] --- Activity

1 Activity是什么 ​​Activity​​是一个Android的应用组件&#xff0c;它提供屏幕进行交互。每个Activity都会获得一个用于绘制其用户界面的窗口&#xff0c;窗口可以充满哦屏幕也可以小于屏幕并浮动在其他窗口之上。 一个应用通常是由多个彼此松散联系的Activity组成&…

NFTScan 正式上线 Base NFTScan 浏览器和 NFT API 数据服务

2023 年 8 月 24 号&#xff0c;NFTScan 团队正式对外发布了 Base NFTScan 基础设施&#xff0c;将为 Base 生态的 NFT 开发者和用户提供简洁高效的 NFT 数据搜索查询服务。NFTScan 作为全球领先的 NFT 数据基础设施服务商&#xff0c;Base 是继 Bitcoin、Ethereum、BNBChain、…

合宙Air724UG LuatOS-Air LVGL API控件--日历 (Calendar)

日历 (Calendar) LVGL 提供了一个用来选择和显示当前日期的日历控件。 示例代码 – 高亮显示的日期 highlightDate lvgl.calendar_date_t() – 日历点击的回调函数 – 将点击日期设置高亮 function event_handler(obj, event) if event lvgl.EVENT_VALUE_CHANGED then da…

Web项目与帆软11集成后通过项目访问cpt文件会弹出数据决策系统登录界面如何取消

1、登录帆软 - 数据决策系统 * 点击 &#xff1a;管理系统 - 模板认证 - 点击设置按钮 - 关闭 2、选择关闭单个认证 你点击后&#xff0c;它默认所有都是开的。你依次点击关闭&#xff0c;然后再把要的模板点击开启&#xff0c;如下图所示&#xff1a;第一个就表示开了认证&am…

vxe-table中树形结构

如图&#xff0c;同事让帮忙实现一个需求 从二级树节点开始&#xff0c;同时选中的只能有一个二级树节点&#xff0c;选中的二级树节点之下的子节点都可以被选中。否则不能被选中 直接上代码 需要注意的是&#xff0c;文中树状图传递的数据是打平的数据&#xff0c;设置代码是…

[集创赛海云捷讯杯]全国二等奖经验分享

[集创赛海云捷讯杯]全国二等奖经验分享 一.前言二.我们的作品三.小结 一.前言 笔者是研一在校生&#xff0c;从五月份开始和本科生一起卷集创赛&#xff0c;经历初赛&#xff0c;分赛区决赛&#xff0c;全国总决赛&#xff0c;认识了很多一起做比赛的朋友收获颇丰。今年海云杯…

记录一次可视化大屏开发

版本&#xff1a;echarts5.3.0 - echarts-gl2.0.8 echarts大部分问题都是版本原因&#xff0c;4.x和5.x区别很大&#xff0c;推荐^5.3.0&#xff0c;因为有些api需要这个版本以上才支持。另外5.1支持svg地图数据格式&#xff0c;与之前的一些用法截然不同&#xff0c;同时拓展性…

(动态规划) 剑指 Offer 60. n个骰子的点数 ——【Leetcode每日一题】

❓ 剑指 Offer 60. n个骰子的点数 难度&#xff1a;中等 把 n 个骰子扔在地上&#xff0c;所有骰子朝上一面的点数之和为 s 。输入 n&#xff0c;打印出s的所有可能的值出现的概率。 你需要用一个浮点数数组返回答案&#xff0c;其中第 i 个元素代表这 n 个骰子所能掷出的点…

国民八路参考文献:[8]许少辉.乡村振兴战略下传统村落文化旅游设计[M]北京:中国建筑工业出版社,2022.

国民八路参考文献&#xff1a;&#xff3b;&#xff18;&#xff3d;许少辉&#xff0e;乡村振兴战略下传统村落文化旅游设计&#xff3b;&#xff2d;&#xff3d;北京&#xff1a;中国建筑工业出版社&#xff0c;&#xff12;&#xff10;&#xff12;&#xff12;&#xff0…

Grid布局详解-看这篇就够了

Grid网格布局的概念&#xff0c;和flex布局的区别 含义&#xff1a;它将网页划分成一个个网格&#xff0c;可以任意组合不同的网格&#xff0c;做出各种各样的布局 区别&#xff1a;Gid布局与Flex布局有一定的相似性&#xff0c;都可以指定容器内部多个项目的位置。但是&#…

Autosar存储入门系列04_NvM的CRC比较机制及同/异步写

本文框架 0.前言1. NvM的CRC校验1.1 CRC 比较机制 2. NvM的同步写及异步写2.1 NvM的同步写2.1 NvM的异步写 0.前言 本系列是Autosar存储入门系列&#xff0c;希望能从学习者的角度把存储相关的知识点梳理一遍&#xff0c;这个过程中如果大家觉得有讲得不对或者不够清晰的地方&…

【09期】HashMap常见面试题

简介 HashMap最早出现在JDK1.2中&#xff0c;底层基于散列算法实现。HashMap 允许 null 键和 null 值&#xff0c;是非线程安全类&#xff0c;在多线程环境下可能会存在问题。 1.8版本的HashMap数据结构&#xff1a; 为什么有的是链表有的是红黑树&#xff1f; 默认链表长度大…

Postman脚本批量转接口自动化用例

1、前言 作者之前已经开发了一个生成接口用例的工具 - API接口用例生成器&#xff0c;即将现有的 Postman 脚本转化为接口用例。本篇介绍另一款最近刚开发并项目落地的工具&#xff0c;将 Postman 的 json 脚本文件可以批量转换生成接口用例 - APICase-PostmanForJSON。 2、简…

jmeter接口测试及详细步骤以及项目实战教程

在接口测试项目实战中&#xff0c;JMeter是一款非常强大和流行的自动化测试工具&#xff0c;它可以测试各种类型的应用程序&#xff0c;并通过采样和报告来识别性能瓶颈和API的问题。本文将为你提供一个基于实际项目的JMeter接口测试项目实战教程&#xff0c;指导你如何使用JMe…

驱动day10

练习 基于platform实现 设备树 myplatform_homework{compatible "hqyj,myplatform_homework"; //用于获取节点reg <0x12345678 14>;interrupt-parent <&gpiof>; //引用父节点interrupts <9 0>; //这个节点引入的中断管脚led1-gpi…

Git 简单介绍

Git 是一个开源的分布式版本控制系统&#xff0c;用于敏捷高效地处理任何或小或大的项目。 一、Git 安装 windows安装&#xff1a;进入网站 https://git-scm.com/ 安装&#xff0c;ubuntu配置&#xff1a;apt install git。当前于 Win 下已安装 Git 版本 2.40.1。 二、配置 设…

ModStartBlog v8.1.0 博客密码访问,内容编辑升级

ModStart 是一个基于 Laravel 模块化极速开发框架。模块市场拥有丰富的功能应用&#xff0c;支持后台一键快速安装&#xff0c;让开发者能快的实现业务功能开发。 系统完全开源&#xff0c;基于 Apache 2.0 开源协议。 功能特性 丰富的模块市场&#xff0c;后台一键快速安装 …

LLMs之Code:SQLCoder的简介、安装、使用方法之详细攻略

LLMs之Code&#xff1a;SQLCoder的简介、安装、使用方法之详细攻略 目录 SQLCoder的简介 1、结果 2、按问题类别的结果 SQLCoder的安装 1、硬件要求 2、下载模型权重 3、使用SQLCoder 4、Colab中运行SQLCoder 第一步&#xff0c;配置环境 第二步&#xff0c;测试 第…

Jetson Xavier NX安装torch环境

设备简介 Jetson Xavier NX是一款具有强大计算能力的AI处理器&#xff0c;它采用了NVIDIA的Turing架构和Volta GPU架构&#xff0c;可以实现高性能的深度学习和推理任务。具体性能如下&#xff1a; CPU&#xff1a;6核心ARM Cortex-A57处理器&#xff0c;最高主频1.5GHz。 GP…

一文讲透 JavaScript 应用的演进历程

在不断发展的软件开发领域中&#xff0c;很少有编程语言像JavaScript一样产生深远的影响。它起初只是一种简单的脚本语言&#xff0c;但如今已成为现代Web的驱动力量&#xff0c;改变了应用构建和体验的方式。本文将带你沿着时间线&#xff0c;穿越JavaScript的演进历程&#x…