集合源码1

news2024/10/7 0:27:23

一、List接口分析

1、list接口的特点

①List集合的所有元素是由一种线性方式进行存储的。

②它是一个元素存储有序的集合。即元素的存入顺序和取出顺序有保证。

③他是一个带有索引的集合,通过索引就可以精确的操作集合中的元素

④集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素

1.1List接口的主要实现类

①ArrayList:动态数组

②Vector:动态数组

③LinkedList:双向列表

④Stack:栈

2、ArrayList与Vector的区别

他们底层的物理结构都是数组,我们称为动态数组

①ArrayList是新版的动态数组,线程不安全,效率高,Vector是旧版的动态数组,线程安全,效率低。

②动态数组的扩容机制不同,ArrayList默认扩容为原来的1.5倍,Vector默认扩容增加为原来的2倍

③数组的初始化容量,如果在构建ArrayList与Vector的集合对象,没有显式指定初始化容量

        ●Vector初始化默认为10,ArrayList在jdk6.0及之前的版本也是10

        ●JDK8.0之后的版本ArrayList初始化长度为0的空数组,之后在添加第一个元素时,再创建长度为10的数组。

ArrayList和LinkedList的区别总结如下:

●ArrayList底层使用了动态数组实现,实质上是一个动态数组

●LinkedList底层使用了双向列表实现,可当作堆栈、队列、双端队列使用

●ArrayList在随机存取方面的效率高于LinkedList

●LinkedList在节点的增删方面效率高于ArrayList

●ArrayList必须预留一定的空间,当空间不足时,会进行扩容操作

●LinkedList的开销是必须存储节点的信息以及节点的指针信息

ArrayList的实现原理是动态数组,它是线程不安全的,允许其中元素为null。ArrayList实现了 List, RandomAccess, Cloneable, java.io.Serializable接口,如下所示:

其中RandomAccess代表了其拥有随机快速访问的能力,ArrayList可以以O(1)的时间复杂度去根据下标访问元素。

3、常用API

/*
 * ①AbstractList<E>是一个抽象类,它提供了List接口的骨架实现,以最小化实现此接口所需的工作。
 * 继承AbstractList使得ArrList无需从头开始实现list接口中中的所有方法,只需要关注那些与动态数组特性紧密相关的方法。
 * ②List<E>接口,继承自Collection<E>接口,有序,可重复
 * ③RandomAccess是一个标记接口,不包含任何方法。它用来声明实现该接口的列表类支持快速随机访问。ArrayList
 * 基于动态数组实现,因此可以高效的通过使用索引访问元素(时间复杂度为O(1)).实现RandomAccess可以作为一种提示,
 * 告诉算法或集合操作可以用更高效的方式来遍历或操作这个列表
 * ④Cloneable是一个标记接口,它本身不包含任何方法。他的存在主要是为了在运行时由Object类的clone方法检查
 * 对象是否可以被克隆。如果一个类没有实现Cloneable接口,并且尝试调用其对象的clone()方法,那么会抛出一个
 * CloneNotSupportedException异常
 * clone()方法。Object类提供的,用于创建并返回调用该方法对象的一个副本。只有实现了Cloneable接口的对象
 * 才能被克隆。
 *ArrayList中的clone()方法
 * ArrayList实现了Cloneable接口,并覆盖了Object类的clone()方法以提供自己的实现。当你调用ArrayList对
 * 象的clone()方法是,他会创建一个新的ArrayList实例,这个新实例包含原始列表中所有元素的浅拷贝。
 * 浅拷贝:在 ArrayList 的上下文中,浅拷贝意味着新列表中的元素是原始列表中元素的引用,而不是元素本身的副本。
 * 修改了新列表中某个元素的状态,那么原始列表中对应的元素也会受到影响,因为它们实际上指向内存中的同一个对象。
 * 深拷贝:不仅复制对象本身,还复制对象中的引用类型字段所指向的对象
 * ⑤Serializable 接口也是一个标记接口,用于启用其实现类的序列化机制。序列化是将对象的状态信息转换为可以
 * 保存或传输的形式的过程。ArrayList 实现 Serializable 接口,意味着其实例可以被序列化为字节流,进而可
 * 以保存到文件、数据库或通过网络发送到另一个运行环境中的另一个 Java 虚拟机。这对于分布式应用或需要将对象
 * 状态持久化到存储介质的场景非常有用。
 *
 * @param <E>
 */
public class ArrayList1<E>extends AbstractList<E>
        implements List<E>, RandomAccess,Cloneable, java.io.Serializable {
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    /*
     *      transient关键字用于声明一个字段不应该是对象序列化的的一部分,当你将一个对象的状态保存到文件,数据库
     * 或通网络发送时,这个过程称为序列化(serialization)。这个过程对象被转换成一系列字节,序列化的目的是将对
     * 象的状态信息转换成可以存储或传输的格式,以便稍后可以通过反序列化恢复对象的状态
     *       transient在private transient Object[] elementData;中的作用是避免序列化过程中不必要的数据膨胀
     * 特别是处理动态数组或集合时,这些数据结构可能包含大量未使用的空间,通过使用transient,开发者可以精确控制那
     * 些数据应该被序列化,从而优化性能和减少存储需求
     *
     */
//属性
private transient Object[] elementData;//存储底层的数组元素
 private int size; //记录数组中存储的元素的个数
    //构造器
    private ArrayList1(){
      this(10); //指定初始容量为10
    }

    @Override
    public int size() {
        return 0;
    }

    public ArrayList1(int initialCapacity){
        /*
         * 子类的构造方法必须首先调用父类的构造方法,这是因为子类在创建时必须首先调用父类的构造方法。这是
         *  因为子类在创建时,首先需要初始化从父类继承的部分
         */
        super();
        //检查初始容量的合法性
        if (initialCapacity<0)
            throw new IllegalArgumentException("Illegal Capacity:"+initialCapacity);
            //数组初始化长度为initialCapacity的数组
            this.elementData=new Object[initialCapacity];
        }
    //add()相关方法
    public boolean add(E e){
        ensureCapacityInternal(size+1);//查看当前数组是否能够多存一个元素
        elementData[size++]=e;//将元素e添加到elementData数组中
        return true;
    }
//检查当前数组的容量elementDate.length是否小于minCapacity
    private void ensureCapacityInternal(int minCapacity) {
        /*
         *  modCount用于支持快速失败机制,快速失败机制是Java集合中的一种迭代器行为,当迭代器创建之后,如果在
         *  迭代过程中检测的集合的结构被修改(非通过迭代器自身的remove或add方法),则抛出
         *  ConcurrentModificationException异常,这里的被修改指的是集合的大小发生变化,或者某些方式改变了
         *  集合的迭代顺序,使得迭代器无法按照预期的方式遍历集合
         *  集合的结构发生变化是指集合的元素和顺序变化
         */
        modCount++; //集合被修改的次数
        //如果if条件满足,则进行扩容
        if (minCapacity-elementData.length>0)
        /*
         * minCapacity在ArrayList上下文中表示最小容量,即ArrayList底层数组将要添加元素后所需达到的最小容量
         *如果小于,说明当前数组容量不足,需要进行扩容,此时会调用grow(int minCapacity)
         * 如果不小于,则直接进行添加操作
         */
            grow(minCapacity);
    }
/**
 * 扩容动态数组
 */
    private void grow(int minCapacity) {
        int oldCapacity= elementData.length;
        /*
         * 新数组容量是旧数组容量的1.5;
         * oldCapacity>>1:这是一个位运算操作,具体是右移一位,在二进制表示中,右移一位相当于/2
         * 这里使用位运算符>>1是因为她等同于oldCapacity/2,但位运算通常更快
         */
        int newCapacity=oldCapacity+(oldCapacity>>1);
        //判断就数组的1.5倍是否超过最大数组限制,
        // 如果超过了最大数组限制,会调用hugeCapacity(minCapacity)来计算一个新的合适的容量
        if (newCapacity-MAX_ARRAY_SIZE>0)
            newCapacity=hugeCapacity(minCapacity);
        //复制一个新数组,
        // 使用Arrays.copyOf方法创建一个新的数组,将旧数组的内容复制到新数组中,
        // 并更新elementData引用指向新数组
        /*
         * Arrays.copyOf(T[] original,int newLength)方法是用来创建一个新数组,他的内容是原始数组的
         * 一个副本,但是新数组的长度是由第二个参数指定,这个方法常用于在需要扩展或缩小数组大小时使用。
         *
         * 这个新数组的引用被赋值给了elementDate变量。这样elementDate变量就指向了一个新的,
         * 长度不同的数组(如果newCapacity大于原始数组的长度,则新数组中剩余的位置将被初始化为
         * 该类型的默认值,对于对象数组,这些位置将是null)
         */
        elementData= Arrays.copyOf(elementData,newCapacity);
    }

    /*
     * 当所需的最小容量大于MAX_ARRAY_SIZE时,计算一个新的合适的容量
     * @param minCapacity
     * @return
     */
    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) //overflow
            throw new OutOfMemoryError();
        /*
         * MAX_ARRAY_SIZE是ArrayList内部定义的常量,它通常背设置为Integer.MAX_VALUE-8(或者类似的值,具体取决于
         * JVM的实现。)这个值是为了确保在创建新数组时,有足够的空间来存储数据
         */
        return (minCapacity>MAX_ARRAY_SIZE)?
                Integer.MAX_VALUE:
                MAX_ARRAY_SIZE; //这是为了防止创建过大的数组而导致内存溢
    }
    //方法:remove的相关方法
    public E remove(int index){
        rangeCheck(index);//判断index是否在有效范围内
        modCount++;//修改次数加1
        //取出index位置的元素,[index]位置的元素就是要被删除的元素
        E oldValue=elementData(index);
        /*
         * 这行代码用于计算当从列表中删除一个元素,需要向后移动的元素数量。
         * 删除这个元素,索引index及之后的元素都需要向前移动一个位置来填补空缺
         * index+1到size-1--->size-1-index
         */
        int numMoved=size-index-1;//确定要移动的次数
        //如果需要移动次数,就用System.arrayCopy移动元素
        if (numMoved>0)
            /*
             *这行代码是把elementData数组中从索引index+1开始的numMoved个元素复制到该数组的
             *index索引开始的位置,这样做的结果是,原来位于index位置处的元素被覆盖(即被删除),
             *而他后面的所有的元素都向前移动了一个位置
             System.arraycopy方法的参数解释:
             ●第一个参数:src(在这里是elementData):源数组
             ●第二个参数:srcPos(index+1):源数组中的起始位置(包含)
             ●第三个参数:dest(elementData):目标数组,(在这种情况下目标数组和源数组是一致的)
             ●第四个参数:destPos(index)目标数组的起始位置(包含)
             ●第五个参数:length(numMoved):要复制的数组元素的数量
             **/
            System.arraycopy(elementData,index+1,elementData,index,numMoved);
        //将elementData[size-1]位置置空,让GC回收空间,元素个数减少
        elementData[--size]=null;
        return oldValue;
    }

    public void rangeCheck(int index)  {
        if (index>=size)
           //throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
            throw new IndexOutOfBoundsException("index"+index+",size"+size);
    }
    E elementData(int index){
        return (E)elementData[index];
}

//方法:set()方法相关
    public E set (int index, E element){
        rangeCheck(index);//检验index是否合法
        //取出【index】位置的元素,【index】位置的元素就是要被替换的元素,用于最后返回被替换的元素
        E oldValue=elementData(index);
        //用element替换【index】处的元素
        elementData[index]=element;
        return oldValue;
    }
    //方法:get()相关方法
    public E get(int index){
        rangeCheck(index);//检验index是否合法
        return elementData(index);//返回index位置的元素
    }
    //方法:indexOf()
    public int indexOf(Object o){
        //分为o是否为空两种情况
        if (o==null){
            for (int i = 0; i < size; i++)
                if (elementData[i]==null)
                    return i;

        }else{
            for (int i = 0; i < size; i++)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    //lastIndexOf()
    public int lastIndexOf(Object o){
        //分为o是否为空两种情况
        if (o==null){
            //从后往前找
            for (int i = size-1; i >=0 ; i--)
                if (elementData[i]==null)
                    return i;
        }else{
            for (int i = size-1; i >=0 ; i--)
                if (o.equals(elementData[i]))
                    return i;
        }
        return -1;
    }
    //contains方法
    public boolean contains(Object o){
        return indexOf(o)>=0;
    }
    //clear方法
    public void clear(){
        modCount++;
        for (int i = 0; i < size; i++) {
            elementData[i]=null;
            size=0;
        }
    }
    /*
    public int size(){
        return size;
    }
     */
    public boolean isEmpty(){
        return size==0;
    }

    //toArray方法
    public Object[] toArray(){
        return Arrays.copyOf(elementData,size);
    }

    public <T> T[] toArray(T [] a){
        //如果传入数组a的大小小于集合的大小,则创建一个新的数组
        if (a.length<size)
            //使用Arrays.copyOf创建一个新的数组,其类型与a相同,大小为size
            //注意:这里需要强制类型转化(T[]),但由于类型信息在运行时丢失,所以可能会抛出ClassCastException
            //注意:使用@SuppressWarnings("unchecked")来抑制这个警告
            return (T[]) Arrays.copyOf(elementData, size, a.getClass());
            //如果传入的数组a的大小足够大,则直接使用它
            System.arraycopy(elementData, 0, a, 0, size);
            //如果传入的数组a的大小大于集合的大小,则将多余的元素设置为null
            if (a.length > size)
                a[size] = null;
            //返回填充了集合元素的数组
            return a;
        }
        //迭代器Iterator

    public Iterator<E> iterator(){
        return new Itr();
    }
//检查迭代器是否还有更多的元素可以遍历
    public class Itr implements Iterator<E>{
        //表示迭代器当前遍历到的位置
    //在迭代开始时,cursor通常被初始化为指向集合的第一个元素(在ArrayList集合中,他可能被初始化为0)
    //随着next的调用,cursor会递增以指向下一个元素
int cursor;
/*
lastRet用于记录上一次调用next()方法时返回的元素的索引。它被初始化为-1,表示第一次调用
next()之前,没有元素被返回
 */
int lastRet=-1;
/*
expectedModCount字段迭代器创建集合的修改次数。这是快速失败机制的一部分,用于检测在迭代
过程中集合是否被并发修改
 */
int expectedModCount=modCount;//用于判断集合是否修改过的标志
        @Override
        public boolean hasNext() {
           // 它检查 cursor 是否不等于 size。如果不等,表示还有更多的元素可以遍历,因此方法返回
            // true;如果相等,表示没有更多的元素,因此方法返回 false。
            return cursor!=size;
        }
@SuppressWarnings("unchecked")
        @Override
        public E next() {
            //检查集合是否被并发修改
            checkForComodification();
            int i=cursor;
            //检查cursor是否越界
          if (i>=size) //判断是否越界
              throw new NoSuchElementException();
          //获取集合的底层数组,并再次检查cursor是否越界
          Object []elementData=ArrayList1.this.elementData;
          if (i>=elementData.length)//再次判断是否越界,在我们这里的操作时
              throw new ConcurrentModificationException();
          //递增cursor
          cursor=i+1;//游标+1
    //更新lastRet为当前元素的索引,进行类型转换后并返回该元素
    return (E)elementData[lastRet=i];
        }
        //从集合中移除最后一个通过迭代器返回的元素
public void remove(){
            /*
            检查lastRet是否有效
             */
            if (lastRet<0)
                throw new IllegalStateException();
           /*
            检查集合的并发修改
            用于检查迭代器自创建以来是否被修改过,如果迭代器被非迭代器方法修改过,则抛异常
            这是迭代器的一个常见特性,用于保证迭代过程中的集合一致性
            */
            checkForComodification();
            try{
                /*
                移除元素
                 */
                ArrayList1.this.remove(lastRet);//删除元素 remove方法内会修改modCount,所以后面要更新Iterator里的标志词
                //要删除的游标
                cursor=lastRet;
                //不能重复删除 所以修改删除的标志位
                lastRet=-1;
                //更新  判断集合是否修改的标志
                expectedModCount=modCount;
            }catch (IndexOutOfBoundsException ex){
                throw new ConcurrentModificationException();
            }

}
//用于检查迭代过程中集合是否被并发修改,如果有修改,则抛出异常
        private void checkForComodification() {
            if (modCount!=expectedModCount)
                throw new ConcurrentModificationException();
        }
    }

    }

迭代器是一个内部类,包括Itr和ListItr

Iterator和ListIterator的区别如下:

①前者可以遍历list和set集合,后者只能用来遍历list集合

②前者只能前向遍历集合;后者可以前向和后向遍历集合

③后者实现了前者,增加了一些新的功能

ArrayList源码总结

①ArrayList内部基于动态数组实现,所以可以进行扩容操作,每一次扩容增量都是50%,

②基于数组实现,所以内部多个API都避免不了对数组的copy操作,比如set和remove操作,所以大桥欧治ArrayList插入和删除效率低下

③基于数组实现,并且实现了RandomAccess,所以可以随机访问,根据index来找元素的致,所以ArrayList获取元素的效率很高

④提供了多个迭代器,都是基于内部类实现的

⑤底层源码没有做同步处理,所以是线程不安全的,之前版本Vector原理基本一致,但是Vector在方法的实现上都会加上synchronized关键字

⑥modeCount会在适当的时候进行++操作,可以实现快速失败

什么是快速失败?

快速失败(fail-fast)是编程中的一个概念,特别是在处理集合(如Java中的List、Set等)时尤为重要。它指的是在程序运行过程中,当某个线程正在遍历集合(通过迭代器Iterator)时,如果集合的内容被其他线程所修改(如添加、删除元素),则遍历过程会立即感知到这种变化,并抛出ConcurrentModificationException异常,从而中断遍历。这种机制的主要目的是让程序能够尽早地报告潜在的问题,帮助开发人员快速定位并修复问题,保证系统的可靠性和稳定性。

快速失败的好处

快速定位问题:通过立即抛出异常,开发人员可以迅速知道集合在迭代过程中被修改了,从而更容易地定位问题所在。

保证系统可靠性:防止因为集合内容的不一致而导致后续操作出现错误,保证系统的稳定性和可靠性。

快速失败的缺点

快速失败机制虽然能够尽早地暴露问题并帮助开发人员快速定位修复,但也存在一些缺点,如可能导致程序中断、用户体验差、可能掩盖真正的问题、增加系统复杂性以及不适用于所有场景等。

Vector类简介

1、Vector类是单列集合List接口的一个实现类。与ArrayList类似,Vector也实现了一个可以动态修改的数组。两者最本质的区别在于-------Vector类是支持线程同步的,因此它线程安全,支持多线程,而ArrayList是线程不同步的,线程不安全。

2、Vector内部是以动态十足的形式来存储数据的。

3、Vector具有动态数组所具有的特性,通过索引支持随机访问,所以通过随机访问Vector中的元素效率非常高,但是执行插入删除时效率比较低。

4、Vector实现了AbstractList抽象类,List接口,所以其更具有了AbstractList和List的功能,前面我们知道AbstractList实现了

内部已经实现了获取Iterator和ListIterator的方法、所以Vector只需关心对数组操作的方法的实现、

        5、Vector实现了RandomAccess接口、此接口只有声明、没有方法体、表示Vector支持随机访问。

        6、Vector实现了Cloneable接口、此接口只有声明、没有方法体、表示Vector支持克隆。

        7、Vector实现了Serializable接口、此接口只有声明、没有方法体、表示Vector支持序列化、即可以将Vector以流的形式通过ObjectOutputStream来写入到流中。

        8、Vector是线程安全的。

Vector类属于Java.base模块,Java.util包下

线程同步是什么意思?

线程同步是指多个线程在访问共享资源时,按照一定的顺序或规则来执行,以避免数据竞争和冲突,确保数据的一致性和完整性。具体来说,当一个线程在对某个内存地址(通常是共享资源)进行操作时,其他线程不能同时对该内存地址进行操作,直到该线程完成操作并释放资源后,其他线程才能继续操作。线程同步的目的是为了避免数据混乱,解决与时间有关的错误,确保多个线程能够协调工作,达到一致性的状态。

为什么ArrayList线程不安全?

ArrayList线程不安全的原因主要有以下几点:

  1. 非同步机制:ArrayList没有实现任何同步机制,这意味着多个线程可以同时访问和修改ArrayList中的数据,而没有任何锁或其他同步机制来确保数据的一致性。
  2. 基于数组的实现:ArrayList底层是通过数组来实现的,而数组的长度是固定的。当进行增删操作时,需要改变数组的长度,这可能会导致多个线程同时操作同一个数组,从而引发线程安全问题。
  3. 数据不一致:如果多个线程同时对ArrayList进行写操作(如add、remove等),可能会导致数据不一致的情况。例如,一个线程正在修改一个元素,而另一个线程正在读取该元素,这时就会出现数据不一致的情况。
  4. 索引越界:如果多个线程同时进行添加或删除元素操作,就可能导致索引越界的情况。例如,一个线程正在删除ArrayList中最后一个元素,而另一个线程正在向ArrayList中添加元素,这时就可能导致索引越界。
Vector线程安全?

Vector是线程安全的,但需要注意的是,这种线程安全是相对的,并且有一定的局限性。Vector通过在其方法上添加synchronized关键字来实现线程安全,这意味着当一个线程在调用Vector的某个同步方法时,其他线程不能同时调用该同步方法。然而,这种同步机制只保证了Vector的单个方法是线程安全的,并不能保证多个线程在调用不同方法时的整体安全性。

此外,虽然Vector是线程安全的,但在高并发场景下,其性能可能会受到影响。因为synchronized关键字会导致线程在访问同步方法时进行阻塞和唤醒操作,这会增加线程切换的开销。因此,在需要高并发性能的场合,通常会选择使用其他并发集合,如ConcurrentHashMap、CopyOnWriteArrayList等。

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

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

相关文章

二分查找算法——寻找旋转排序数组中的最小值点名

1.题目解析 题目来源&#xff1a;LCR173.点名——力扣 原名&#xff1a;剑指offer——0~n-1中消失的数字 测试用例 题目来源&#xff1a;153.寻找旋转排序数组中的最小值——力扣 测试用例 2.算法原理 点名 如果要寻找消失的数字&#xff0c;可以判断对应下标的数字是否和下标对…

视觉定位Revisit Anything

Revisit Anything: Visual Place Recognition via Image Segment Retrieval 项目地址 摘要&#xff1a; 准确识别重游地点对于嵌入代理的定位和导航至关重要。这要求视觉表现清晰&#xff0c;尽管摄像机视点和场景外观有很大变化。现有的视觉地点识别管道对“整个”图像进行编码…

制作离线版Koczkatamas工具包

一、下载源码 从https://github.com/koczkatamas/koczkatamas.github.io下载koczkatamas.github.io-master.zip 二、解压 $ unzip koczkatamas.github.io-master.zip三、运行index.html 可以看到输入一个字符后&#xff0c;下面的各种编码都没有显示&#xff0c;则表示运行…

【玩转 JS 函数式编程_008】3.1.2 JavaScript 函数式编程筑基之:箭头函数——一种更流行的写法

文章目录 3.1.2 箭头函数——更流行的方式 Arrow functions - the modern way1. 返回值 Returning values2. this 值的处理 Handling the this value3. arguments 的处理 Working with arguments4. 单参数还是多参数&#xff1f; One argument or many? 写在前面 故天将降大任…

儿童需要学习C++多久才能参加信息学奥赛的CSP-J比赛?

信息学奥赛&#xff08;NOI&#xff09;是国内编程竞赛领域的顶尖赛事&#xff0c;而对于初学者来说&#xff0c;参加NOI的第一步通常是通过CSP-J&#xff08;全国青少年信息学奥林匹克联赛初赛&#xff09;&#xff0c;这也是面向青少年程序员的入门级竞赛。作为信息学奥赛的基…

vue3使用three.js加载.obj模型示例

vue3使用three.js加载.obj模型示例 效果&#xff1a; 代码&#xff1a; 需要先安装three.js npm install three<template><div ref"threeContainer" class"three-container"></div> </template><script> import * as TH…

男单新老对决:林诗栋VS马龙,巅峰之战

听闻了那场激动人心的新老对决&#xff0c;不禁让人热血沸腾。在这场乒乓球的巅峰之战中&#xff0c;林诗栋与马龙的对决无疑是一场视觉与技术的盛宴。 3:3的决胜局&#xff0c;两位选手的每一次挥拍都充满了策略与智慧&#xff0c;他们的每一次得分都让人心跳加速。 林诗栋&am…

10.6学习

1.Hystrix / Sentinel ●服务雪崩场景 自己即是服务消费者&#xff0c;同时也是服务提供者&#xff0c;同步调用等待结果导致资源耗尽 ●解决方案 服务方&#xff1a;扩容、限流&#xff0c;排查代码问题&#xff0c;增加硬件监控 消费方&#xff1a;使用Hystrix资源隔离&a…

JavaSE——面向对象10:抽象类、接口

目录 一、抽象类 (一)抽象类的引出 (二)抽象类基本介绍 (三)注意事项和使用细节 (四)抽象类的最佳实践——模板设计模式 二、接口 (一)接口快速入门 (二)基本介绍 (三)注意事项与使用细节 (四)接口VS继承 (五)接口的多态性 1.多态参数 2.多态数组 3.接口存在多态…

CoreGen项目实战——代码提交信息生成

数据与相关代码见文末 1.概述 源代码与自然语言之间的语义鸿沟是生成高质量代码提交信息的一个重大挑战。代码提交信息对于开发者来说非常重要,因为它们简明扼要地描述了代码更改的高层次意图,帮助开发人员无需深入了解具体实现即可掌握软件的演变过程。手动编写高质量的提交…

Vite多环境配置与打包:

环境变量必须以VITE开头 1.VITE_BASE_API&#xff1a; 在开发环境中设置为 /dev-api&#xff0c;这是一个本地 mock 地址&#xff0c;通常用于模拟后端接口。 2.VITE_ENABLE_ERUDA&#xff1a; 设置为 "true"&#xff0c;表示启用调试工具&#xff0c;通常是为了…

Elasticsearch学习笔记(六)使用集群令牌将新加点加入集群

随着业务的增长&#xff0c;陆续会有新的节点需要加入集群。当我们在集群中的某个节点上使用命令生成令牌时会出现报错信息。 # 生成令牌 /usr/share/elasticsearch/bin/elasticsearch-create-enrollment-token -s node出现报错信息&#xff1a; Unable to create enrollment…

VMware WorkStation Pro 15.5(低版本安装) 教学用

VMware WorkStation Pro 15.5(低版本安装) 教学用 文章目录 VMware WorkStation Pro 15.5(低版本安装) 教学用前言安装使用 前言 VMware Workstation Pro 15.5 是一款功能强大的桌面虚拟化软件&#xff0c;适用于在单台物理电脑上运行多个操作系统。它被广泛应用于软件开发、测…

【文献阅读】Attention Bottlenecks for Multimodal Fusion

Abstract 在多模态视频分类中&#xff0c;将各模态的最终表示或预测进行后期融合&#xff08;“后期融合”&#xff09;仍然是主流范式。为此&#xff0c;本文提出了一种基于 Transformer 的新型架构&#xff0c;该架构使用“融合瓶颈”在多个层次进行模态融合。与传统的成对自…

科研必备语料库

1. Corpus of Contemporary American English 链接&#xff1a;https://www.english-corpora.org/coca/ 2. Purdue Online Writing Lab 链接&#xff1a;https://owl.purdue.edu/owl/ 3. Academic Phrases and Vocabulary 链接&#xff1a;https://www.ref-n-write.com/blog…

IntelliJ IDE 插件开发 | (十三)自定义项目脚手架(下)

系列文章 本系列文章已收录到专栏&#xff0c;交流群号&#xff1a;689220994&#xff0c;也可点击链接加入。 前言 在上一篇文章中介绍了如何在 IDEA 中自定义项目脚手架&#xff0c;本文将介绍如何在WebStorm、PyCharm、CLion等其它 IntelliJ 主流平台中如何自定义项目脚手…

【论文速看】DL最新进展20241006-视频深度估计、3D、自监督学习

目录 【视频深度估计】【3D】【自监督学习】 【视频深度估计】 [TPAMI 2024] NVDS: Towards Efficient and Versatile Neural Stabilizer for Video Depth Estimation 论文链接&#xff1a;https://arxiv.org/pdf/2307.08695 代码链接&#xff1a;https://github.com/RaymondW…

地理空间数据存储与处理:MySQL空间数据类型的优化与应用!

在 MySQL 数据库中&#xff0c;空间数据类型用于存储和处理地理空间数据。这些数据类型允许我们在开发时可在数据库中存储和操作地理位置、几何形状和地理空间关系等信息。 一、什么是空间数据类型 MySQL 中的空间数据类型主要包括以下几种&#xff1a; GEOMETRY&#xff1a…

【无人水面艇路径跟随控制3】(C++)USV代码阅读: ROS包的构建和管理:包的依赖关系、包含目录、库文件以及链接库

【无人水面艇路径跟随控制3】&#xff08;C&#xff09;USV代码阅读&#xff1a; ROS包的构建和管理&#xff1a;包的依赖关系、包含目录、库文件以及链接库 写在最前面ROS是什么CMakeLists.txt总结详细解释CMake最低版本和项目名称编译选项查找catkin包catkin包配置包含目录添…

(刷题记录5)盛最多水的容器

盛最多水的容器 题目信息&#xff1a;题目思路(环境来自力扣OJ的C)&#xff1a;暴力枚举&#xff1a;双指针&#xff1a;移动高度较高的指针移动高度较低的指针 复杂度&#xff1a;代码与注释&#xff1a;暴力枚举&#xff1a;双指针&#xff1a; 题目信息&#xff1a; 给定一…