Java集合之ArrayList详解

news2024/11/15 8:17:09

Java集合之ArrayList

  • 一、ArrayList类的继承关系
    • 1. 基类功能说明
      • 1.1. Iterator:提供了一种方便、安全、高效的遍历方式。
      • 1.2. Collection:为了使ArrayList具有集合的基本特性和操作。
      • 1.3. AbstractCollection:提供了一些通用的集合操作。
      • 1.4. List:为了让其具有列表的特性和更多的操作。
      • 1.5. Serializable:支持序列化。
      • 1.6. AbstractList:为了使其具有列表的抽象特性和操作。
      • 1.7. RandomAccess:支持随机访问。
      • 1.8. Cloneable:支持克隆操作。
  • 二、ArrayList的优缺点
    • 1. 优点:
      • 1.1. 速度快:支持通过下标访问
      • 1.2. 高效的元素添加和删除:支持在末尾添加和删除
      • 1.3. 可以存储任何类型的对象:基本类型和自定义类型
      • 1.4. 可以动态扩容:使用起来非常灵活
    • 2. 缺点:
      • 2.1. 频繁的插入和删除操作开销较大:涉及元素移动
      • 2.2. 内存浪费:容量设置过大,存在浪费内存空间
      • 2.3. 不支持多线程操作:多线程下不安全
      • 2.4. 查询和删除操作效率低:查询指定元素,需要依次遍历
  • 三、ArrayList源码分析
    • 1. 基本属性
      • 1.1 DEFAULT_CAPACITY
      • 1.2 EMPTY_ELEMENTDATA
      • 1.3 DEFAULTCAPACITY_EMPTY_ELEMENTDATA
      • 1.4 elementData
      • 1.5 size
    • 2. get方法
    • 3. set方法
    • 4. add方法
      • 4.1 add方法流程图:
    • 5. remove方法
      • 5.1 remove(int index):
      • 5.2 remove(Object o):
      • 5.3 fastRemove(int index):
    • 6. clear方法
  • 四、ArrayList三种遍历方式
    • 1、使用for循环遍历
    • 2、通过下标遍历
    • 3、使用Iterator迭代器遍历
    • 4、增强for本质上也是迭代器
  • 五、ArrayList之fail-fast 和fail-safe机制
    • 1. fail-fast:Java集合当中的一种错误检测机制
      • 1.1 简述:ConcurrentModificationException
      • 1.2 原理:modCount#expectedModCount
      • 1.3 使用场景:
      • 1.4 注意:
    • 2. fail-safe:集合被修改时创建副本,保证线程安全
      • 2.1. 简述:拷贝集合
      • 2.2. 原理:拷贝集合
      • 2.3. 使用场景:
        • 2.3.1 多线程环境下的并发读写操作:
        • 2.3.2 数据量较小且读操作较多的场景:
        • 2.3.3 不要求强一致性的场景:
      • 2.4. 注意:
      • 2.5. 扩展:集合容器对比
        • 2.5.1. ArrayList#CopyOnWriteArrayList
        • 2.5.2. LinkedList#CopyOnWriteArrayList
        • 2.5.3. HashMap#ConcurrentHashMap
        • 2.5.4. TreeMap#ConcurrentSkipListMap
        • 2.5.6. HashSet#ConcurrentHashMap
        • 2.5.7. TreeSet#ConcurrentSkipListSet
  • 六、ArrayList在多线程下如何使其线程安全
    • 1. 使用 Vector 代替 ArrayList。
    • 2. 使用Collections.synchronizedList()方法。
    • 3. 使用CopyOnWriteArrayList。
    • 4. 使用Lock。
  • 八、ArrayList的序列化机制
    • 1. 自定义序列化机制 readObject、writeObject
    • 2. 为什么用transient修饰elementData数组

一、ArrayList类的继承关系

jicheng

1. 基类功能说明

1.1. Iterator:提供了一种方便、安全、高效的遍历方式。

  1. Iterator是一个迭代器接口,它提供了一种安全的遍历集合元素的方法,可以避免在遍历过程中修改集合引起的ConcurrentModificationException异常,同时还可以避免在遍历过程中删除集合元素时出现索引越界等问题。

  2. ArrayList使用Iterator遍历集合时,可以使用hasNext()方法判断是否还有元素,使用next()方法获取下一个元素,使用remove()方法安全地删除当前元素。因此,使用Iterator遍历ArrayList既方便又安全,是一种非常推荐的遍历方式。

  3. 另外,Iterator接口是Java集合框架中的一部分,实现Iterator接口可以使ArrayList更加符合集合框架的统一标准,方便与其他集合类一起使用。

1.2. Collection:为了使ArrayList具有集合的基本特性和操作。

  1. ArrayList是Java中常用的集合类之一,它实现了Collection接口,这是为了使ArrayList具有集合的基本特性和操作,例如添加、删除、遍历等。
  2. 实现Collection接口可以让ArrayList能够和其他Java集合类兼容,可以方便地进行集合之间的转换和使用。同时,实现Collection接口也使得ArrayList能够支持泛型,可以在编译期间进行类型检查,避免了运行时出现类型错误的问题。
  3. 总之,ArrayList实现Collection接口是为了使其具有更多的特性和更好的兼容性。

1.3. AbstractCollection:提供了一些通用的集合操作。

  1. 例如containsAll、removeAll、retainAll等方法,这些方法可以被ArrayList直接继承和使用,从而避免了重复实现这些操作。
  2. 同时,AbstractCollection也提供了一些抽象方法,例如size、iterator、toArray等方法,这些方法需要由具体的集合类去实现,ArrayList也需要实现这些方法以完成自身的功能。

1.4. List:为了让其具有列表的特性和更多的操作。

  1. ArrayList实现了List接口,是为了使其具有列表的特性和操作,例如按索引访问元素、插入、删除、替换等。List是Collection接口的子接口,提供了更多针对列表的操作。
  2. 例如按索引操作、排序、子列表等。因此,实现List接口可以让ArrayList具有更多的操作和更好的兼容性,可以和其他实现List接口的Java集合类进行交互和转换。

1.5. Serializable:支持序列化。

  1. 序列化是将对象转换为字节流的过程,可以用于持久化对象、网络传输等操作。实现Serializable接口可以让ArrayList的实例对象被序列化,以便于在需要的时候进行序列化操作。

1.6. AbstractList:为了使其具有列表的抽象特性和操作。

  1. AbstractList是List接口的一个抽象实现,实现了List接口的大部分方法,包括添加、删除、获取元素、遍历等。

  2. ArrayList作为List接口的一个具体实现,需要实现List接口中定义的所有方法。

  3. 通过继承AbstractList抽象类,ArrayList可以重用AbstractList中已经实现的方法,减少重复代码,提高代码的复用性和可维护性。

  4. 另外,AbstractList还提供了一些抽象方法,例如get()、set()、add()、remove()等,这些抽象方法需要ArrayList子类实现,从而使得ArrayList具备列表的基本操作。

  5. AbstractList还提供了一些模板方法,例如addAll()、removeAll()等,这些方法可以通过调用抽象方法实现具体的操作。通过继承AbstractList抽象类,ArrayList可以利用这些模板方法快速实现各种列表操作,提高了开发效率。

综上所述,ArrayList实现了AbstractList抽象类是为了重用AbstractList中已经实现的方法,提高代码的复用性和可维护性,同时也能够利用AbstractList中提供的模板方法快速实现各种列表操作。

1.7. RandomAccess:支持随机访问。

  1. ArrayList实现了RandomAccess接口,是为了提高随机访问的效率。RandomAccess接口是一个标记接口,用于表示实现该接口的集合支持快速随机访问,即可以通过下标直接访问集合中的元素,而不需要通过迭代器进行遍历。

  2. 对于ArrayList来说,它是一个基于数组实现的列表,因此可以通过下标直接访问数组中的元素。实现RandomAccess接口可以让ArrayList在随机访问时使用高效的数组访问方式,从而提高随机访问的效率。

  3. 如果一个集合没有实现RandomAccess接口,那么在进行随机访问时,会通过迭代器遍历集合中的元素,这个过程比直接访问数组的效率要低。因此,在需要频繁进行随机访问的情况下,实现RandomAccess接口可以大大提高访问效率。

  4. 需要注意的是,实现RandomAccess接口并不一定能提高集合的效率,它只是表明该集合支持快速随机访问的特性,具体效率的提升还要看具体的实现。

1.8. Cloneable:支持克隆操作。

  1. Cloneable接口是一个标记接口,用于表示实现该接口的对象可以进行克隆操作。

  2. 在ArrayList中,克隆操作可以用于创建一个与原列表相同的新列表,这个新列表与原列表相互独立,对新列表的修改不会影响到原列表。这在某些场景下非常有用,例如需要对一个列表进行操作,但是又需要保留原列表不变的情况下,可以先克隆出一个新列表进行操作。

  3. 需要注意的是,ArrayList实现Cloneable接口只是表示它支持克隆操作,并不代表它的克隆操作一定是完全正确和安全的。在进行克隆操作时,需要注意可能存在的浅拷贝和深拷贝问题,以及可能会影响到对象的不变性和线程安全性问题等。

  4. 因此,在使用ArrayList的克隆操作时,需要仔细考虑其对程序的影响,并进行必要的安全性和正确性检查。

二、ArrayList的优缺点

1. 优点:

1.1. 速度快:支持通过下标访问

由于ArrayList底层是基于数组实现的,因此查询和随机访问速度非常快,时间复杂度为O(1)。

1.2. 高效的元素添加和删除:支持在末尾添加和删除

ArrayList支持在末尾添加和删除元素的操作,时间复杂度为O(1),因此在操作上非常高效。

1.3. 可以存储任何类型的对象:基本类型和自定义类型

ArrayList可以存储任何类型的对象,包括基本类型和自定义类型。

1.4. 可以动态扩容:使用起来非常灵活

ArrayList可以根据需要动态地扩展容量,因此它非常灵活。

2. 缺点:

2.1. 频繁的插入和删除操作开销较大:涉及元素移动

由于ArrayList底层是基于数组实现的,因此在进行频繁的插入和删除操作时,需要移动大量的元素,时间复杂度为O(n),开销较大。

2.2. 内存浪费:容量设置过大,存在浪费内存空间

由于ArrayList是基于数组实现的,因此在创建ArrayList时需要指定初始容量,如果容量设置过大,就会浪费内存空间。

2.3. 不支持多线程操作:多线程下不安全

由于ArrayList不是线程安全的,因此在多线程环境下需要进行额外的同步操作,否则会出现线程安全问题。

2.4. 查询和删除操作效率低:查询指定元素,需要依次遍历

当需要查询和删除某个元素时,需要遍历整个ArrayList,时间复杂度为O(n)。

三、ArrayList源码分析

1. 基本属性

1.1 DEFAULT_CAPACITY

默认初始容量,没什么可说的。

/**
 * Default initial capacity.
 */
private static final int DEFAULT_CAPACITY = 10;

1.2 EMPTY_ELEMENTDATA

空实例数组。

/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

1.3 DEFAULTCAPACITY_EMPTY_ELEMENTDATA

默认大小的空实例数组,在第一次调用ensureCapacityInternal方法时会初始化长度为10

/**
 * Shared empty array instance used for default sized empty instances. We
 * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
 * first element is added.
 */
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

1.4 elementData

存放元素的数组。

/**
 * The array buffer into which the elements of the ArrayList are stored.
 * The capacity of the ArrayList is the length of this array buffer. Any
 * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
 * will be expanded to DEFAULT_CAPACITY when the first element is added.
 */
transient Object[] elementData; // non-private to simplify nested class access

1.5 size

当前数据中有多少元素

/**
 * The size of the ArrayList (the number of elements it contains).
 *
 * @serial
 */
private int size;

2. get方法

public E get(int index) {
    rangeCheck(index);
    return elementData(index);
}
private void rangeCheck(int index) {
	if (index >= size)
    	throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
}
E elementData(int index) {
    return (E) elementData[index];
}
  1. 根据传入的下标
  2. 调用rangeCheck方法检查下标是否越界
  3. 由于底层是数组,可以直接根据index获取elementData数组对应下标位置的元素

3. set方法

public E set(int index, E element) {
    rangeCheck(index);
    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}
E elementData(int index) {
    return (E) elementData[index];
}
  1. 根据传入的下标index和元素element
  2. 调用rangeCheck方法检查下标是否越界
  3. 获取当前elementData数组对应的老数据
  4. 将当前元素,根据传入小标放入数组中指定位置
  5. 将当前下标对应的老数据进行返回

4. add方法

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    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++;
    // overflow-conscious code
    if (minCapacity - elementData.length > 0)
        grow(minCapacity);
}
private void grow(int minCapacity) {
    // overflow-conscious code
    int 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);
}
private static int hugeCapacity(int minCapacity) {
     if (minCapacity < 0) // overflow
         throw new OutOfMemoryError();
     return (minCapacity > MAX_ARRAY_SIZE) ?
         Integer.MAX_VALUE :
         MAX_ARRAY_SIZE;
 }

4.1 add方法流程图:

add

5. remove方法

public E remove(int index) {
    rangeCheck(index);
    modCount++;
    E oldValue = elementData(index);
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
    return oldValue;
}
public boolean remove(Object o) {
   if (o == null) {
       for (int index = 0; index < size; index++)
           if (elementData[index] == null) {
               fastRemove(index);
               return true;
           }
   } else {
       for (int index = 0; index < size; index++)
           if (o.equals(elementData[index])) {
               fastRemove(index);
               return true;
           }
   }
   return false;
}
private void fastRemove(int index) {
    modCount++;
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

5.1 remove(int index):

  1. 检查下标是否越界。
  2. 将modCount+1,计算需要移动的元素个数
  3. 如果需要移动,将index+1位置及之后的所有元素,向左移动一个位置。
  4. 将size-1位置的元素赋值为空(因为上面将元素左移了,所以size-1位置的元素为重复的,将其移除)。

5.2 remove(Object o):

  1. 如果传入元素为null,遍历数组,查找第一个为null的元素。
    1.1. 调用fastRemove()方法。
    1.2 移除成功,返回true。
  2. 如果传入元素不为null,则遍历数组查找是否存在元素与入参元素使用equals比较返回true。
    2.1. 如果存在则调用fastRemove将该元素移除,并返回true表示移除成功
  3. 不存在目标元素,返回false

5.3 fastRemove(int index):

1.将modCount修改次数+1。
2. 计算需要移动的元素个数numMoved 。
3. 调用System.arraycopy,开始移动。
4. 将size-1,并将size-1位置的元素赋值为空。(否则存在重复元素)

6. clear方法

public void clear() {
     modCount++;
     // clear to let GC do its work
     for (int i = 0; i < size; i++)
         elementData[i] = null;
     size = 0;
 }
  1. 将modCount+1。
  2. 遍历数组将所有元素设置为null。
  3. size元素数量置为0。

四、ArrayList三种遍历方式

1、使用for循环遍历

ArrayList<String> list = new ArrayList<String>();
// 添加元素
for (String str : list) {
    System.out.println(str);
}

2、通过下标遍历

ArrayList<String> list = new ArrayList<String>();
// 添加元素
for (int i = 0; i < list.size(); i++) {
    System.out.println(list.get(i));
}

3、使用Iterator迭代器遍历

ArrayList<String> list = new ArrayList<String>();
// 添加元素
Iterator<String> it = list.iterator();
while (it.hasNext()) {
    System.out.println(it.next());
}

4、增强for本质上也是迭代器

123

五、ArrayList之fail-fast 和fail-safe机制

1. fail-fast:Java集合当中的一种错误检测机制

1.1 简述:ConcurrentModificationException

  1. Java集合中的快速失败机制是通过在集合结构发生变化时,及时检查并发修改的情况,如果发现其他线程正在遍历该集合,就立即抛出ConcurrentModificationException异常,以防止并发修改导致数据不一致的问题。

1.2 原理:modCount#expectedModCount

  1. 当使用迭代器遍历集合时,会使用一个预期修改次数(expectedModCount)变量来记录当前集合的修改次数(modCount)。每次调用next()方法时,都会先检查expectedModCount和modCount是否相等。如果相等,则说明在遍历过程中没有发生并发修改,可以返回下一个元素;如果不相等,则说明在遍历过程中有其他线程进行了修改,就会抛出ConcurrentModificationException异常。

  2. 在集合结构发生变化时,会修改modCount的值,这样在遍历过程中就能够检测到并发修改情况。具体来说,当调用add()、remove()、clear()等方法时,会修改modCount的值,如果此时有其他线程正在遍历集合,则会在下一次遍历时检测到并抛出异常。

  3. 总的来说,Java集合中的快速失败机制是通过预期修改次数和实际修改次数的比较来检测并发修改的情况。这种机制虽然会增加一定的开销,但能够保证数据的一致性和可靠性。

1.3 使用场景:

java.util包下的集合类都是快速失败的,不能在多线程下发生并发修改(迭代过程中被修改)

1.4 注意:

  1. 如果集合发生变化时修改modCount值刚好又设置为了expectedmodCount,就会导致迭代器没有检测到集合结构的变化,而继续执行下去,这样可能会引起数据不一致的问题。例如,如果集合中有两个相同的元素,但是在迭代过程中只返回了其中一个,这样就会导致数据不一致的问题。

2. fail-safe:集合被修改时创建副本,保证线程安全

2.1. 简述:拷贝集合

  1. 采用安全失败机制的集合容器,在遍历时不是直接在集合内容上访问的,而是先复制原有集合内容,在拷贝的集合上进行遍历。

2.2. 原理:拷贝集合

  1. 修改时不在原集合上做操作,而是基于原集合copy一个新的集合,在新的集合上做数据变动,会存在短暂的数据不一致问题。

2.3. 使用场景:

2.3.1 多线程环境下的并发读写操作:

使用fail-safe机制的集合类可以保证多个线程同时对集合进行读写操作时,不会出现并发修改异常,而且各个线程之间的访问不会相互阻塞。

2.3.2 数据量较小且读操作较多的场景:

由于fail-safe机制的集合类在进行读操作时不会阻塞其他线程的访问,因此适合于数据量较小且读操作较多的场景,比如缓存、配置信息等。

2.3.3 不要求强一致性的场景:

由于fail-safe机制的集合类使用了弱一致性迭代器,因此不能保证在迭代过程中能够看到所有修改之后的元素,适合于不要求强一致性的场景。

2.4. 注意:

使用fail-safe机制的集合类可能会对性能产生一定的影响,因此在对性能要求比较高的场景下,应该谨慎选择。同时,在使用fail-safe机制的集合类时,也需要注意它们的线程安全性和一致性问题。

2.5. 扩展:集合容器对比

2.5.1. ArrayList#CopyOnWriteArrayList

  1. ArrayList:ArrayList是一个可变数组,它的内部实现是一个数组,线程不安全,在多线程环境下要使用线程安全的集合类,比如CopyOnWriteArrayList。

2.5.2. LinkedList#CopyOnWriteArrayList

  1. LinkedList:LinkedList是一个链表,线程不安全,在多线程环境下要使用线程安全的集合类,比如CopyOnWriteArrayList。

2.5.3. HashMap#ConcurrentHashMap

  1. HashMap:HashMap是一个哈希表,线程不安全,在多线程环境下要使用线程安全的集合类,比如ConcurrentHashMap。

2.5.4. TreeMap#ConcurrentSkipListMap

  1. TreeMap:TreeMap是一个有序的键值对集合,线程不安全,在多线程环境下要使用线程安全的集合类,比如ConcurrentSkipListMap。

2.5.6. HashSet#ConcurrentHashMap

  1. HashSet:HashSet是一个哈希表,线程不安全,在多线程环境下要使用线程安全的集合类,比如ConcurrentHashMap的keySet方法返回的Set集合。

2.5.7. TreeSet#ConcurrentSkipListSet

  1. TreeSet:TreeSet是一个有序的集合,线程不安全,在多线程环境下要使用线程安全的集合类,比如ConcurrentSkipListSet。

六、ArrayList在多线程下如何使其线程安全

1. 使用 Vector 代替 ArrayList。

  1. 不推荐,Vector是一个历史遗留类。
  2. 具体来说,Vector是通过 synchronized 关键字来实现线程安全的,这意味着每次对Vector进行修改时,都需要获得对象级别的锁,这会导致多个线程之间频繁地竞争锁,从而降低了程序的性能。

2. 使用Collections.synchronizedList()方法。

  1. 该方法可以将一个非线程安全的ArrayList转换为线程安全的List,但是需要注意,对于多个并发访问的线程,需要对整个List进行同步操作。

3. 使用CopyOnWriteArrayList。

  1. 该类是一个线程安全的集合类,它在对集合进行修改时,会先将原来的集合复制一份,然后对复制后的集合进行修改。
  2. 这样可以避免竞态条件和不可见性的问题,但是会消耗额外的空间和时间开销。

4. 使用Lock。

  1. 可以使用java.util.concurrent.locks包中的Lock接口进行同步操作,保证多个线程对ArrayList的互斥访问。
  2. 但是需要注意,使用Lock可能会导致死锁等问题,需要仔细考虑锁的粒度和范围。

八、ArrayList的序列化机制

1. 自定义序列化机制 readObject、writeObject

  1. ArrayList通过两个方法readObject、writeObject自定义序列化和反序列化策略,实际直接使用两个流ObjectOutputStream和ObjectInputStream来进行序列化和反序列化。

2. 为什么用transient修饰elementData数组

  1. 出于效率的考虑,数组可能长度10,但实际只用了3个位置,剩下的7个位置空闲,其实不用序列化,这样可以提高序列化和反序列化的效率,还可以节省内存空间。

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

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

相关文章

Vue-动画效果

vue动画效果 vue中动画效果是很简单的一个东西&#xff0c;vue帮助我们做了一些动画封装&#xff0c;同时也支持自定义动画&#xff0c;过度&#xff0c;第三方库&#xff0c;这些方式都可以实现&#xff0c;我们一一举例说明 注意&#xff1a;下面的相关截图&#xff0c;由于…

55 KVM工具使用指南-LibcarePlus概述

文章目录 55 KVM工具使用指南-LibcarePlus概述55.1 概述55.2 软硬件要求55.3 注意事项和约束 55 KVM工具使用指南-LibcarePlus概述 55.1 概述 LibcarePlus 是一个用户态进程热补丁框架&#xff0c;可以在不重启进程的情况下对 Linux 系统上运行的目标进程进行热补丁操作。热补…

语音合成 - TTS-VUE 学习

今天给小伙伴测试了一款人工智能文字合成语音的工具&#xff0c;测试中发现应该是某位大神开发的开源工具&#xff0c;经过一下午的测试&#xff0c;发现有可学习之处&#xff0c;有兴趣的小伙伴可以一起来学习下。 一、简单介绍 微软的语音合成助手利用强大的微软AI语音库&am…

牛云企业官网小程序,外卖cps权益变现,uniCloud云开发无需购买服务器和域名,助力每一位创业者。

技术优势 基于 uniapp uniCloud 研发&#xff0c;无需购买服务器和域名&#xff0c;uniCloud 是 DCloud 联合阿里云、腾讯云 serverless 构建。从此不用关心服务器运维、弹性扩容、大并发承载、防DDoS攻击等&#xff0c;轻松应对高并发应用&#xff0c; 上图 小程序页面 体…

一种新颖的智能优化算法-蝠鲼优化算法(MRFO)

目录 一、MRFO数学模型 1.1 链式觅食 1.2 旋风式觅食 1.3 翻筋斗式觅食 二、MRFO伪代码 2019年提出一种新的仿生优化技术称为魔鬼鱼觅食优化算法&#xff0c;旨在提供一种替代优化 解决实际工程问题的方法。该算法的灵感是基于智能算法魔鬼鱼的行为。这项工作模拟了魔鬼…

轻量应用服务器性能如何?CPU带宽流量系统盘测评

轻量应用服务器性能如何&#xff1f;腾讯云轻量应用服务器是一种轻量级搭建小型网站和应用的服务器&#xff0c;相对于其他更高性能配置的服务器CVM&#xff0c;性价比更高。虽然其性能不如高性能云服务器CVM&#xff0c;但对于小型网站和应用来说&#xff0c;能够提供基本的计…

JDK1.8 lambda_函数式编程_stream流

一、 lambda表达式 jdk 1.8 引入了 lambda表达式 能够我们 编写代码时更加简洁,也为函数式编程提供了支持 lambda表达式 作用 简化匿名实现类的书写&#xff0c;实现接口抽象方法&#xff1b; (参数类型 参数名1,参数类型 参数名2,……参数类型 参数名n)->{ //方法体 } …

【工具】搜狗输入法常用配置(持续更新)

▒ 目录 ▒ &#x1f6eb; 问题描述环境 1️⃣ 按键相关通用快捷键系统快捷键辅助输入快捷键 2️⃣ 其它自定义语句关闭自动更新 &#x1f6ec; 结论 &#x1f6eb; 问题 描述 作为输入法的常青树&#xff0c;重装系统后经常第一步就是装输入法&#xff0c;由于以下原因&#…

开发框架前后端分离的好处是什么

关于将前端和后端保持在一起或分开&#xff0c;存在广泛的意见分歧。唯一重要的是&#xff0c;这两个组件对于开发成熟的应用程序都是必需的。 考虑&#xff1a;紧密耦合的前端和后端 许多人认为后端和前端的分离是一个坏主意&#xff0c;这两个角色之间没有太大区别。 以下…

多旋翼无人机振动分析与减振方法

多旋翼无人机振动分析与减振方法 振动分析无人机减振设计机械减振数字滤波减振 振动分析 振动机制包括&#xff1a; 激励&#xff08;振动源&#xff09;系统响应 无人机振动机制&#xff1a; 激励 —— 动力系统&#xff08;旋翼电机&#xff09;系统 —— 机架响应 —— …

《产品思维》 要点

“一切以用户价值为依归”的价值观&#xff0c;落地下来就是从用户中来&#xff0c;到用户中去。 认知用户 用户画像 用户是一切产品的源头 用户不是理性人 我们的用户到底是谁、究 竟在哪里。这个“到底是谁”“究竟在哪里”。 用户生活工作的环境&#xff0c;是他们日常的…

【机器学习】机器故障的二元分类模型-Kaggle竞赛

竞赛介绍 数据集描述 本次竞赛的数据集&#xff08;训练和测试&#xff09;是从根据机器故障预测训练的深度学习模型生成的。特征分布与原始分布接近&#xff0c;但不完全相同。随意使用原始数据集作为本次竞赛的一部分&#xff0c;既可以探索差异&#xff0c;也可以了解在训…

[RockertMQ] Broker启动加载消息文件以及恢复数据源码 (三)

Broker的启动过程中, 在DefaultMessageStore实例化后, 会调用load方法将磁盘中的commitLog、ConsumeQueue、IndexFile文件的数据加载到内存中, 还有数据恢复的操作。 调用isTempFileExist方法判断上次broker是否是正常退出, 如果是正常退出不会保留abort文件, 异常退出则会。 …

【MySQL】关于自增id、雪花id还是uuid作为MySQL主键

在MySQL中设计表的时候&#xff0c;MySQL官方推荐不要使用uuid或者不连续不重复的雪花id(long型且唯一)&#xff0c;而是推荐连续自增的主键id&#xff0c;官方的推荐是auto_increment。那么为什么不使用雪花id或者uuid呢&#xff1f;让我们来探讨分析一下这个问题的原因。 关于…

【人工智能技术专题】「入门到精通系列教程」打好AI基础带你进军人工智能领域的全流程技术体系(机器学习知识导论)

零基础带你进军人工智能领域的全流程技术体系和实战指南&#xff08;机器学习基础知识&#xff09; 前言专栏介绍专栏说明学习大纲前提条件面向读者学习目标核心内容机器学习的概念定义回顾人工智能机器学习概念国外知名学者对机器学习的定义中文翻译 机器学习发展历程机器学习…

Oracle JSON_ARRAYAGG()函数的排序失效问题

引入&#xff1a; 在实际操作中&#xff0c;俺写了这样一个Funtcion&#xff1a; FUNCTION fun_get_xxx(v_param_one VARCHAR2) RETURN CLOB ASv_OUTPUT CLOB;BEGINWITH temp_table AS (SELECT * FROM (( SELECT one.action_id,two.log_timeFROM table_one oneLEFT JOIN table…

【深度学习】6-4 卷积神经网络 - CNN的实现

CNN的实现 网络的构成是“Convolution - ReLU - Pooling -Affine - ReLU - Affine - Softmax”&#xff0c;我们将它实现为名为 SimpleConvNet的类。 首先来看一下 SimpleConvNet的初始化&#xff08;init&#xff09;&#xff0c;取下面这些参数。 input_dim——输入数据的维…

七彩虹CN600+Meetiger N10C测评

七彩虹CN600这款M.2固态硬盘的参数就不多说了 本期采用为512版本 迷虎品牌&#xff0c;英文名Meetiger&#xff0c;Meetiger/迷虎品牌成立于2012年&#xff0c;品牌迷虎产品主要有硬盘底座,保护盒,硬盘座,移动硬盘盒子,硬盘盒子,... 以下就是本期的硬盘盒 当这两样东西在一起…

C++(10):泛型算法

泛型算法&#xff1a;可用于不同类型的容器和不同类型的元素的通用算法。 概述 大多数算法都定义在头文件algorithm 中。标准库在头文件 numeric 中定义了一组数值泛型算法。 一般情况下&#xff0c;泛型算法不直接操作容器&#xff0c;而是遍历由两个迭代器指定的一个元素范…

【Spring Boot学习】日志文件,Spring Boot也会写日记了,这些事你知道嘛 ? ? ?

前言: 大家好,我是良辰丫,在上一篇文章中我们已经学习了Spring Boot的配置,接下来我们要学习一些日志相关的东西,什么是日志呢?我们慢慢往下看.&#x1f48c;&#x1f48c;&#x1f48c; &#x1f9d1;个人主页&#xff1a;良辰针不戳 &#x1f4d6;所属专栏&#xff1a;javaE…