Java集合类源码分析(四):ArrayList&LinkedList

Java解析p12文件 做公司项目遇到了关于GoogleBigQuery的问题,而要使用这个服务需要一个证书,要求支持json和p12文件两种格式。这里主要记录一下如何从p12文件中读取出公钥和私钥信息。 import sun.misc.BASE64Encoder; import java.security.KeyStore; import java.security.PrivateKey; import java... 阅读详情

我的github:xjwhhh的github
希望大家多多关注,共同进步

Java集合类源码分析(一):Collcetion接口
Java集合类源码分析(二):List接口
Java集合类源码分析(三):AbstractList类
Java集合类源码分析(四):ArrayList&LinkedList
java集合类源码分析(五):Map接口
Java集合类源码分析(六):AbstractMap类
Java集合类源码分析(七):HashMap&LinkedHashMap
Java集合类源码分析(八):AbstractSet类
Java集合类源码分析(九):HashSet&LinkedHashSet

ArrayList源码分析

ArrayList可以放入任何类型的元素
ArrayList不是同步的

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

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

/**
 * 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 = {};

/**
 * 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

构造函数,如果传入的初始容量大于0,就构造一个数组,否则使用类里本来有的静态空数组

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() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

构造一个ArrayList,含有集合里的所有元素,顺序与集合迭代器返回的元素顺序相同
如果集合为空,则直接使用静态空数组

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;
    }
}

将列表的容量调整到与元素数量相同,可以用来最小化存储空间

public void trimToSize() {
    modCount++;
    if (size < elementData.length) {
        elementData = (size == 0)
          ? EMPTY_ELEMENTDATA
          : Arrays.copyOf(elementData, size);
    }
}

增大列表容量

public void ensureCapacity(int minCapacity) {
    int minExpand = (elementData != DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
        // any size if not default element table
        ? 0
        // larger than default for default empty table. It's already
        // supposed to be at default size.
        : DEFAULT_CAPACITY;

    if (minCapacity > minExpand) {
        ensureExplicitCapacity(minCapacity);
    }
}

private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

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

将新的容量变为原来容量的1.5倍。

但是需要对扩容后的容量进行检验。共有两种可能

1.得到的容量比需要的容量小,即溢出。

2.得到的容量超过了规定的最大容量,进入hugeCapacity中,如果需要的容量小于0,抛出内存溢出异常,如果需要的容量比规定的最大容量大,那么最大容量只能是 Integer.MAX_VALUE。

最后将elementData 通过Array的复制拷贝方法进行了扩容。

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

/**
 * 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
 */
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;
}

返回一个原列表的浅拷贝,即没有拷贝元素

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

返回一个含有列表所有元素的数组

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

@SuppressWarnings("unchecked")
public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}

调用ensureCapacityInternal(size + 1)

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

删除列表中第一个与参数元素相同的元素

 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;
}

用来删除的私有方法,跳过边界检查,也不返回删除的元素

ArrayList对列表的结构性修改,都是调用System.arrayCopy拷贝一部分不变的元素实现的

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
}

根据参数complement决定是保存还是删除列表中与参数列表中相同的元素

首先对集合中的对象数组进行了一次复制,然后将数组中的元素依次与collection进行对比。try{}块的结果就是得到了一个数组,数组前w位元素或与collection相同(complement=true的时候)或不同(complement=false)。

下面来看finally,先来看第二个if{}代码块,它的作用就是把数组中w以后的元素全部变为null值,让gc来回收。

现在回到finally的第一个if中,看条件(r != size),似乎永远不会满足这个条件吧。上面的for循环一直r++啊,可是别忘了,c.contains(elementData[r])这句话是有可能抛出异常的,如果一旦类型不匹配,就会抛出异常 进入finally中。
这个方法,如果没有删除任何数据,那么将会返回false。

public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}

public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, true);
}

private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    int r = 0, w = 0;
    boolean modified = false;
    try {
        for (; r < size; r++)
            if (c.contains(elementData[r]) == complement)
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        if (r != size) {
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        if (w != size) {
            // clear to let GC do its work
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}

将列表写入输出流

private void writeObject(java.io.ObjectOutputStream s)
    throws java.io.IOException{
    // Write out element count, and any hidden stuff
    int expectedModCount = modCount;
    s.defaultWriteObject();

    // Write out size as capacity for behavioural compatibility with clone()
    s.writeInt(size);

    // Write out all elements in the proper order.
    for (int i=0; i<size; i++) {
        s.writeObject(elementData[i]);
    }

    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

由输入流获得列表信息

private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    elementData = EMPTY_ELEMENTDATA;

    // Read in size, and any hidden stuff
    s.defaultReadObject();

    // Read in capacity
    s.readInt(); // ignored

    if (size > 0) {
        // be like clone(), allocate array based upon size not capacity
        ensureCapacityInternal(size);

        Object[] a = elementData;
        // Read in all elements in the proper order.
        for (int i=0; i<size; i++) {
            a[i] = s.readObject();
        }
    }
}

迭代所有,每个元素都执行Consumer中定义的方法,可能会改变元素的值

@Override
public void forEach(Consumer<? super E> action) {
    Objects.requireNonNull(action);
    final int expectedModCount = modCount;
    @SuppressWarnings("unchecked")
    final E[] elementData = (E[]) this.elementData;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        action.accept(elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
}

删除符合过滤器要求的元素

@Override
public boolean removeIf(Predicate<? super E> filter) {
    Objects.requireNonNull(filter);
    // figure out which elements are to be removed
    // any exception thrown from the filter predicate at this stage
    // will leave the collection unmodified
    int removeCount = 0;
    final BitSet removeSet = new BitSet(size);
    final int expectedModCount = modCount;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        @SuppressWarnings("unchecked")
        final E element = (E) elementData[i];
        if (filter.test(element)) {
            removeSet.set(i);
            removeCount++;
        }
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }

    // shift surviving elements left over the spaces left by removed elements
    final boolean anyToRemove = removeCount > 0;
    if (anyToRemove) {
        final int newSize = size - removeCount;
        for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
            i = removeSet.nextClearBit(i);
            elementData[j] = elementData[i];
        }
        for (int k=newSize; k < size; k++) {
            elementData[k] = null;  // Let gc do its work
        }
        this.size = newSize;
        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
        modCount++;
    }

    return anyToRemove;
}

替换所有元素,即对所有元素进行operator定义的操作

@Override
@SuppressWarnings("unchecked")
public void replaceAll(UnaryOperator<E> operator) {
    Objects.requireNonNull(operator);
    final int expectedModCount = modCount;
    final int size = this.size;
    for (int i=0; modCount == expectedModCount && i < size; i++) {
        elementData[i] = operator.apply((E) elementData[i]);
    }
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

排序

@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
    final int expectedModCount = modCount;
    Arrays.sort((E[]) elementData, 0, size, c);
    if (modCount != expectedModCount) {
        throw new ConcurrentModificationException();
    }
    modCount++;
}

LinkedList源码分析

双向链表

不是同步的


transient int size = 0;

//指向第一个结点的指针
    /**
     * Pointer to first node.
     * Invariant: (first == null && last == null) ||
     *            (first.prev == null && first.item != null)
     */
    transient Node first;

//指向最后一个结点的指针
    /**
     * Pointer to last node.
     * Invariant: (first == null && last == null) ||
     *            (last.next == null && last.item != null)
     */
    transient Node last;
public LinkedList() {
}

使用集合创建列表,列表含有集合中所有元素,顺序与集合迭代器返回的元素顺序相同

public LinkedList(Collection<? extends E> c) {
    this();
    addAll(c);
}

将参数元素连接到首位

private void linkFirst(E e) {
    final Node<E> f = first;
    final Node<E> newNode = new Node<>(null, e, f);
    first = newNode;
    if (f == null)
        last = newNode;
    else
        f.prev = newNode;
    size++;
    modCount++;
}

将参数元素连接到最后一位

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;
    else
        l.next = newNode;
    size++;
    modCount++;
}

在第二个参数节点之前插入一个新节点
1. 创建newNode节点,将newNode的后继指针指向succ,前驱指针指向pred
2. 将succ的前驱指针指向newNode
3. 根据pred是否为null,进行不同操作。
- 如果pred为null,说明该节点插入在头节点之前,要重置first头节点
- 如果pred不为null,那么直接将pred的后继指针指向newNode即可

void linkBefore(E e, Node<E> succ) {
    // assert succ != null;
    final Node<E> pred = succ.prev;
    final Node<E> newNode = new Node<>(pred, e, succ);
    succ.prev = newNode;
    if (pred == null)
        first = newNode;
    else
        pred.next = newNode;
    size++;
    modCount++;
}

解除第一个元素的链接

private E unlinkFirst(Node<E> f) {
    // assert f == first && f != null;
    final E element = f.item;
    final Node<E> next = f.next;
    f.item = null;
    f.next = null; // help GC
    first = next;
    if (next == null)
        last = null;
    else
        next.prev = null;
    size--;
    modCount++;
    return element;
}

解除最后一个元素的链接

private E unlinkLast(Node<E> l) {
    // assert l == last && l != null;
    final E element = l.item;
    final Node<E> prev = l.prev;
    l.item = null;
    l.prev = null; // help GC
    last = prev;
    if (prev == null)
        first = null;
    else
        prev.next = null;
    size--;
    modCount++;
    return element;
}

删除某个元素的链接

E unlink(Node<E> x) {
    // assert x != null;
    final E element = x.item;
    final Node<E> next = x.next;
    final Node<E> prev = x.prev;

    if (prev == null) {
        first = next;
    } else {
        prev.next = next;
        x.prev = null;
    }

    if (next == null) {
        last = prev;
    } else {
        next.prev = prev;
        x.next = null;
    }

    x.item = null;
    size--;
    modCount++;
    return element;
}

返回列表的第一个节点

public E getFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return f.item;
}

返回列表的最后一个节点

public E getLast() {
    final Node<E> l = last;
    if (l == null)
        throw new NoSuchElementException();
    return l.item;
}

删除并返回列表的第一个节点

public E removeFirst() {
    final Node<E> f = first;
    if (f == null)
        throw new NoSuchElementException();
    return unlinkFirst(f);
}

删除并返回列表的最后一个节点

public E removeLast() {
    final Node<E> l = last;
    if (l == null)
        throw new NoSuchElementException();
    return unlinkLast(l);
}

将参数元素连接到首位

public void addFirst(E e) {
    linkFirst(e);
}

将参数元素连接到最后一位

public void addLast(E e) {
    linkLast(e);
}

将参数元素连接到列表最后一位,与addLast效果相同

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

如果列表中含有参数元素,则删除它的第一次出现

public boolean remove(Object o) {
    if (o == null) {
        for (Node<E> x = first; x != null; x = x.next) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = first; x != null; x = x.next) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}

将集合中的元素全部加入列表中

public boolean addAll(Collection<? extends E> c) {
    return addAll(size, c);
}

在指定位置处,插入集合中的所有元素,顺序与集合迭代器返回元素顺序相同
1. 检查index索引范围
2. 得到集合数据
3. 得到插入位置的前驱和后继节点
4. 遍历数据,将数据插入到指定位置

public boolean addAll(int index, Collection<? extends E> c) {
    checkPositionIndex(index);

    Object[] a = c.toArray();
    int numNew = a.length;
    if (numNew == 0)
        return false;

    Node<E> pred, succ;
    if (index == size) {
        succ = null;
        pred = last;
    } else {
        succ = node(index);
        pred = succ.prev;
    }

    for (Object o : a) {
        @SuppressWarnings("unchecked") E e = (E) o;
        Node<E> newNode = new Node<>(pred, e, null);
        if (pred == null)
            first = newNode;
        else
            pred.next = newNode;
        pred = newNode;
    }

    if (succ == null) {
        last = pred;
    } else {
        pred.next = succ;
        succ.prev = pred;
    }

    size += numNew;
    modCount++;
    return true;
}
  1. 检查index的范围,否则抛出异常
  2. 如果插入位置是链表尾部,那么调用linkLast方法
  3. 如果插入位置是链表中间,那么调用linkBefore方法

    public void add(int index, E element) {
    checkPositionIndex(index);

    if (index == size)
        linkLast(element);
    else
        linkBefore(element, node(index));
    

    }

返回链表的头部结点

public E peek() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
}

返回链表的头部结点

public E element() {
    return getFirst();
}

删除并返回链表的头部结点

public E poll() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}

删除并返回链表的头部结点

public E remove() {
    return removeFirst();
}

将参数元素连接到链表尾部

public boolean offer(E e) {
    return add(e);
}

将参数元素连接到链表头部

public boolean offerFirst(E e) {
    addFirst(e);
    return true;
}

将参数元素连接到链表尾部

public boolean offerLast(E e) {
    addLast(e);
    return true;
}

返回链表的头部结点

public E peekFirst() {
    final Node<E> f = first;
    return (f == null) ? null : f.item;
 }

返回链表的尾部结点

public E peekLast() {
    final Node<E> l = last;
    return (l == null) ? null : l.item;
}

删除并返回链表的头部结点

public E pollFirst() {
    final Node<E> f = first;
    return (f == null) ? null : unlinkFirst(f);
}

删除并返回链表的头部结点

public E pollLast() {
    final Node<E> l = last;
    return (l == null) ? null : unlinkLast(l);
}

将参数元素连接到链表头部

public void push(E e) {
    addFirst(e);
}

删除并返回链表的头部结点

public E pop() {
    return removeFirst();
}

删除参数元素在链表中的第一次出现

public boolean removeFirstOccurrence(Object o) {
    return remove(o);
}

删除参数元素在链表中的最后一次出现

public boolean removeLastOccurrence(Object o) {
    if (o == null) {
        for (Node<E> x = last; x != null; x = x.prev) {
            if (x.item == null) {
                unlink(x);
                return true;
            }
        }
    } else {
        for (Node<E> x = last; x != null; x = x.prev) {
            if (o.equals(x.item)) {
                unlink(x);
                return true;
            }
        }
    }
    return false;
}

浅拷贝

public Object clone() {
    LinkedList<E> clone = superClone();

    // Put clone into "virgin" state
    clone.first = clone.last = null;
    clone.size = 0;
    clone.modCount = 0;

    // Initialize clone with our elements
    for (Node<E> x = first; x != null; x = x.next)
        clone.add(x.item);

    return clone;
}
阿里巴巴Java开发手册:编程规约.命名风格 命名风格 1.【强制】代码中的命名均不能以下划线或美元符号开始,也不能以下划线或美元符号结束。 反例:name/name/namename / name_ / namename/name/​name /name__ 2.【强制】代码中的命名严禁使用拼音与英文混合的方式,更不允许直接使用中文的方式。 正例:alibaba / taobao / youku / hangzhou 等国际通用的名称,可视... 阅读详情

相关推荐

工业互联网工控安全与工业质检AI大模型建设方案.pptx

工业互联网工控安全与工业质检AI大模型建设方案.pptx

Java总结 - List实现类ArrayList&LinkedList

本文是根据源码进行学习的,如果我有什么理解不对的地方请多指正,谢谢您 上面基本就是List集合类的类图关系了,图中省略掉了比如Cloneable等标记接口,那么List分别具体的主要实现类有:ArrayList,Vector,LinkedList,Stack,那么这篇文章会对这四个实现类进行介绍(由于篇幅原因,本文只说到了ArrayList和Link...

weixin_34054866的博客 77

2024 《计算机网络》实验教学指导书.doc

2024 《计算机网络》实验教学指导书.doc

ArrayList&LinkedList 源码分析

💟这里是CS大白话专场,让枯燥的学习变得有趣!💟没有对象不要怕,我们new一个出来,每天对说不尽情话!

qq_41847894的博客 257

2025华东杯A/B/C题解题思路+可运行代码参考

这些因素包括但不限于:助滑坡的坡度、运动员的质量、滑雪板的接触面与雪地的摩擦力、空气阻力系数、运动员的体型和衣物形态等。助滑坡是运动员滑行至起跳台前的最后一段坡道,这一段坡道的坡度、长度和运动员的姿势会直接影响到起跳时的初始速度。运动员的滑行速度不仅受助滑坡的坡度影响,还受到摩擦力、空气阻力和重力等多方面因素的影响。通过合理的姿势调整,运动员能够有效减少空气阻力,增加身体的重力加速度,进而提升滑行速度。助滑坡的角度通常介于10°到12°之间,而运动员的滑行速度将受到重力、摩擦力和空气阻力的共同作用。

qq_52590045的博客 1796

NMS非极大值抑制算法原理

NMS非极大值抑制算法

pywin 3499

黑马程序员Java面试专题(1)|常见集合篇(1)ArrayList&LinkedList

时间复杂度分析:评估代码的执行耗时复杂度分析:弄清楚代码的执行次数与数据规模n之间的关系。

YOYU_的博客 1578

COMSOL模拟CO2驱替CH4:多物理场耦合建模与工程应用详解

在非常规天然气开发与碳封存工程中,多孔介质内的渗流、吸附与岩石变形相互耦合,使得CO2驱替CH4的产能预测和CO2封存评估无法仅靠经验公式完成。以达西定律描述裂隙流动、以扩展Langmuir方程刻画竞争吸附、用应力-吸附-渗透率关系关联煤岩变形,是多物理场耦合数值模拟的核心路径。COMSOL Multiphysics凭借内置渗流、固体力学与组分传递接口,能够将这些机制整合为可参数化扫描的仿真模型,为注气压力、井距、渗透率演化等方案设计提供量化依据。围绕CO2驱替CH4模拟的建模流程、参数取法与结果判读,可形

weixin_29574585的博客 158

Java Keytool生成数字证书/.cer/.p12文件

任何机构或者个人都可以申请数字证书,并使用由CA机构颁发的数字证书为自己的应用保驾护航。常用的两个证书管理工具:KeyTool,OpenSSL—&gt;构建CSR(Certificate Signing Request,数字证书签发申请),交由CA机构签发,形成最终的数字证书。 最近用到p12文件,就记录一下如何使用jdk自带的keytool来创建p12文件 创建私钥和证书 1.打开cmd,切换到...

devil_bye的博客 1万+

ROS小车定位实战:如何用rf2o_laser_odometry和robot_localization实现精准里程计(附避坑指南)

本文详细介绍了如何利用rf2o_laser_odometry和robot_localization在ROS中实现高精度小车定位。通过激光里程计与状态估计的黄金组合,解决室内移动机器人的定位难题,包括环境搭建、算法配置、多传感器融合策略及实战避坑指南,帮助开发者快速部署稳定可靠的定位系统。

weixin_29081703的博客 285

Wezterm的安装和简单配置

希望 wezterm 的主题配色,保持和 powershell 默认配色一致,也就是 Compell 主题。目的是在频繁使用 wezterm 时,原本的根据颜色判断文件信息(尤其是WSL里的Linux下,文件和目录颜色)依然可以使用。wezterm 默认用 cmd.exe, 我是 win11,希望默认用 powershell。

baiyu33的博客 4264

Java集合类源码分析(三):AbstractList类

AbstractList源码分析 调用了void add(int index, E element),将元素增加在列表末尾。某些列表类会对增加的元素类型有所要求 public boolean add(E e) { add(size(), e); return true; } public E set(int index, E el...

devil_bye的博客 1088

基于STM32设计的水下水质检测装置(微信小程序)(205)

本项目设计了一款基于STM32微控制器为核心的水下水质检测设备,该设备具有高度集成化、智能化的特点,能够实时监测水深、温度、浊度及溶解性总固体(TDS)等关键水质参数,并通过4G网络将数据上传至腾讯云IOT物联网平台,实现远程监控和数据分析。同时,为了便于操作和移动观测,还配套开发了微信小程序,用户可通过微信小程序实时查看并控制设备的各项功能,如调整下潜深度等。

1250

Struts2问题总结

Eclipse下struts2.5环境搭建与struts2.3的区别 在struts2.3中,需要导入导入了9个常用jar包。 (1)struts2-core-2.x.x.jar :Struts 2框架的核心类库 (2)xwork-core-2.x.x.jar :XWork类库,Struts 2在其上构建 (3)ognl-3.x.x.jar :对象图导航语言(Object Gr...

devil_bye的博客 882

华为OD机试 - 统计文本数量(Java 2025 A卷 100分)

华为OD机试 2025A卷题库疯狂收录中,刷题。

学Java,找哪吒 1438

大厂面经:大疆嵌入式面试题及参考答案(4万字长文:持续更新)

目录 Linux 系统调用的过程,中间发生了什么? 表格总结 Linux 中断流程,谈谈你对中断上下文的理解 中断流程 中断上下文理解 Linuxschedule()函数的原理和调用的时机 schedule()函数原理 调用时机 页表实现机制,分页的缺点? 页表机制 分页的缺点 介绍操作系统的多级反馈调度策略,时间片轮转,在项目中如何指定优先级来调度进程完成快速响应(nice命令) 多级反馈队列调度 时间片轮转 使用nice命令 聊内存分配,进程内存分配,段页式存

大模型大数据攻城狮的专栏 4163

Java集合类源码分析(一):Collcetion接口

Collection接口源码分析 int size(); 获取集合长度 boolean isEmpty(); 集合是否不包含任何元素 boolean contains(Object o); 集合是否含有该元素 (o==null?e==null:o.equals(e)) Iterator&amp;amp;lt;E&amp;amp;gt; iterator(); 返回了一个迭代器,这个迭代器的元素顺序是否有...

devil_bye的博客 802

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

阿里巴巴Java开发手册:编程规约.集合处理

1.【强制】关于hashCode和equals的处理,遵循如下规则: 1) 只要重写equals,就必须重写hashCode。 2) 因为Set存储的是不重复的对象,依据hashCode和equals进行判断,所以Set存储的对象必须重写这两个方法。 3) 如果自定义对象作为Map的键,那么必须重写hashCode和equals。 说明:String重写了hashCode和equals方法,所以我...

devil_bye的博客 605

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

OV9734 DATASHEET,完整规格书

OV9734完整规格书,包括电气参数,尺寸规格,寄存器配置表等

阿里巴巴Java开发手册:编程规约.并发处理

2.【强制】创建线程或线程池时请指定有意义的线程名称,方便出错时回溯。 正例:自定义线程工厂,并且根据外部特征进行分组,比如,来自同一机房的调用,把机房编号赋值给whatFeaturOfGroup public class UserThreadFactory implements ThreadFactory { private final String namePrefix; pr...

devil_bye的博客 468

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

阿里巴巴Java开发手册:编程规约.OOP

2.【强制】所有的覆写方法,必须加@Override注解。 说明:getObject()与get0bject()的问题。一个是字母的O,一个是数字的0,加@Override可以准确判断是否覆盖成功,避免外形太像导致覆写失败。另外,如果在抽象类中对方法签名进行修改,其实现类会马上编译报错。 重写发生在运行期,是子类对父类的允许访问的方法的实现过程进行重新编写。返回值类型、方法名、参数列表必须相同,抛...

devil_bye的博客 442

Java集合类源码分析(二):List接口

List接口源码分析 default void replaceAll(UnaryOperator&amp;lt;E&amp;gt; operator) { Objects.requireNonNull(operator); final ListIterator&amp;lt;E&amp;gt; li = this.listIterator(); while (li.hasNext()) { ...

devil_bye的博客 424

Java集合类源码分析(八):AbstractSet类

AbstractSet源码解析 本类没有重写任何AbstractCollection类的方法实现,只是增加了对于equals和hashCode的实现 equals,比较set与参数object是否相等 当且仅当参数object类型是set,两个set有相同长度,并且参数set的每个元素都存在于原set中 public boolean equals(Object o) { if (o...

devil_bye的博客 398

Redis安装与基本使用

Redis安装及基本使用 redis特点 1.Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。 2.Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,sorted-set,hash等数据结构的存储。 3.Redis支持数据的备份,即master-slave模式的数据备份。 redis安装(windows...

devil_bye的博客 382

Java Eclipse问题总结

步骤 1.启动程序时,添加参数 -Xdebug -Xrunjdwp:transport=dt_socket,server=y,address=7899,suspend=n -XDebug 启用调试; -Xrunjdwp 加载JDWP的JPDA参考执行实例; transport 用于在调试程序和VM使用的进程之间通讯; dt_socket 套接字传输; server=y/n VM是否...

devil_bye的博客 363

Java集合类源码分析(六):AbstractMap类

AbstractMap源码解析 提供了对Map接口大致性的实现 如果要实现一个不可修改的map,只需要继承此类并实现entrySet方法。这个set不支持add,remove,它的迭代器也不支持remove 如果要实现一个可修改的map,还要额外重写这个类的put,迭代器也要实现remove public boolean containsValue(Object value) { ...

devil_bye的博客 361

java集合类源码分析(五):Map接口

Map接口源码解析 Map接口的顺序与迭代器在集合角度上的顺序相同,有三种集合角度,分别是键的set,值的集合,和键值对的mappings 一些实现类,如TreeMap,对于顺序做了一些保证,另一些例如HashMap就没有 map不能以map做键,能以map做值,但这样的map对于equals和hashCode方法定义的不好 void putAll(Map&amp;lt;? extends K, ...

devil_bye的博客 352
上一篇: Java集合类源码分析(三):AbstractList类
下一篇: java集合类源码分析(五):Map接口
不晓得X
博客等级 码龄10年 114粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值