安卓开发者必看:Android的数据结构与算法——ArrayList源码解析

android,java整理学习的代码,包括设计模式,算法,数据结构等 java,设计模式,算法,数据结构 立即下载

作者:JerryloveEmily
原文链接:https://www.jianshu.com/p/159426e2aaf6
文章有点长,比较啰嗦,请耐心看完!
一、概述

首先得明白ArrayList在数据结构中是个什么,从名字看,可以直译为“数组集合”,内部得实现八九不离十是用数组来实现的,因此在数据结构中属于线性表结构(0个或者多个元素的有限序列):数据的存储和关系 是这样:

而不是这样的树形的:

iage

ArrayList内部用到了数组来做基本的数据存储结构,那就说明是它一个连续内存块或者存储块的顺序存储结构。

一个连续存储地址的结构

这样的存储结构是优缺点是: **优点:**由于是连续的内存地址存储块,对于查询一个或者多个存储内容,就很容易了,只要找到一个元素的内容a,加上每个元素所占的内存字节数c,a+c就很容易找到下一个元素,计算量小很高效。

**缺点:**缺点也显而易见,举个例子。 a: 你在火车站买票,这个时候,一个漂亮的主播妹纸突然插队到你前面,你和你后面的一起排队的人是不是都得往后退一个位置,妹纸才能插入到你的位置上吧。这个时候这一队中需要挪动位置的人(也就是数组位置)是不是很多,当你和后面排队的人都后退一个位置后,妹纸的插队才算是完成了。这是不是很耗费时间。 b: 你前面的一个哥们突然不想排队走了,空出了一个位置,这时候你和后面排队的人是不是都得往前挪动一个位置,当所有人都挪动完后,这个队伍才恢复原来没有人走的情况,是不是也很耗费时间。

这优缺点要说明的是什么呢,顺序存储的线性表插入和删除的都比较耗费时间,而查询却非常的快。

二、源码解析(Android API 25)

  • ArrayList的类继承关系结构
    ArrayList类继承关系结构.png
  • 构造函数
  /**
     * Constructs an empty list with an initial capacity of ten.
     * 使用10个初始容量构造一个空的集合
     */
    public ArrayList() {
        super();
        // 用一个空的数组进行初始化
        this.elementData = EMPTY_ELEMENTDATA;
    }
  //   来看看  elementData和EMPTY_ELEMENTDATA是什么
  /**
   * Shared empty array instance used for empty instances.
   * 就是一个空数组常量,可是无参的构造的注释又说是内置了10个初始容量,
   * 搞不懂哪里有内置,Google的工程师注释乱写的么,逗我
   */
    private static final Object[] 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 == EMPTY_ELEMENTDATA will be expanded to
     * DEFAULT_CAPACITY when the first element is added.
     * ArrayList的所有元素都存储在elementData这个数组中,
     * 并且ArrayList的容量就是这个缓存数组的长度。
     * 任何一个使用elementData == EMPTY_ELEMENTDATA初始化的空的ArrayList
     *(也就是用 new ArrayList()来构造一个对象的)
     * 在第一次调用add方法的时候,都会被扩充容量到DEFAULT_CAPACITY
     *(原来是在第一次调用add方法的时候用了默认的10作为ArrayList的容量,
     * 看来Android工程师注释不是乱写的)
     * 
     * Package private to allow access from java.util.Collections.
     */
    transient Object[] elementData;

这样的设计也是体现了性能的优化: new ArrayList()构造的时候并没有马上的扩容去申请一堆的Object[] 数据缓存堆内存,而是等到用的时候才去申请。这个性能优化的小技巧可以学习,初始化的时候尽量少开辟还暂时不用的堆内存,等到需要使用的时候再去申请。果然Android工程师都是身经百战的老司机啊,性能优化还的多看看源码好啊。

/**
   * Constructs an empty list with the specified initial capacity.
   *
   * @param  initialCapacity  the initial capacity of the list
   * @throws IllegalArgumentException if the specified initial capacity
   *         is negative
   */
  public ArrayList(int initialCapacity) {
      super();
      if (initialCapacity < 0)
          throw new IllegalArgumentException("Illegal Capacity: "+
                                             initialCapacity);
      this.elementData = new Object[initialCapacity];
  }

这个构造没啥好说的,先检查初始化容量参数的合法性,别整个小于0的容量(不合法就抛出容量参数不合法异常,代码逻辑严谨),根据指定的容量初始化缓存ArrayList数据元素的数组。

/**
   * Constructs a list containing the elements of the specified
   * collection, in the order they are returned by the collection's
   * iterator.
   * 构造一个包含了参数里的集合的ArrayList   
   *
   * @param c the collection whose elements are to be placed into this list
   * @throws NullPointerException if the specified collection is null
   * 传进来的集合如果是null的话会抛出NullPointerException 异常
   */
  public ArrayList(Collection<? extends E> c) {
      elementData = c.toArray();
      size = elementData.length;
      // c.toArray might (incorrectly) not return Object[] (see 6260652)
      if (elementData.getClass() != Object[].class)
          elementData = Arrays.copyOf(elementData, size, Object[].class);
  }

首先把传进来的collection集合转换成Object[]数组对象赋值给内部的数组缓存对象,然后初始化ArrayList的size大小,最后注释写c.toArray可能出错返回的不是Object[], 判断下如果返回的不是Object[]的类类型,就用Object[].class,复制一个Object[]类型的数组给elementData长度是size。

在使用这个构造函数初始化ArrayList的时候,需要注意的是传递的collection不是为null,比如使用的时候:

List<User> userList = null;
List<LoginUser> loginUserList = null;
if(null != userList) {
    loginUserList =new ArrayList(userList);
}

一定得对userList进行先行的判断,不然指不定程序在什么情况下给你来个没女朋友、没对象、没媳妇的异常报错崩溃。据腾讯Bugly报告反馈2016年Android应用崩溃最高的错误异常就是这个NullPointerException 没媳妇了,java就是这么蛋疼凡是使用前都得先做下非空判断。

  • 增删改查 增加 /** * Appends the specified element to the end of this list. * 追加一个元素到集合列表的末尾 * * @param e element to be appended to this list * @return true (as specified by {@link Collection#add}) */ public boolean add(E e) { // 确认内部容量,并增加一次操作计数modCount ensureCapacityInternal(size + 1); // Increments modCount!! // 把新的元素赋值给缓存数组的size位置后size加一, elementData[size++] = e; return true; }

这里需要留意的是add方法并没有判断或者抛出一次说追加进来的e元素不能为null,ArrayList是运行add一个为null的对象的,如下图:

ArrayList是运行add一个为null的对象的

// 确定内部的容量大小
private void ensureCapacityInternal(int minCapacity) {
        // 当使用new ArrayList()构造ArrayList对象的时候,
        // 在第一次add元素(这时候elementData还是一个空的缓存数组),
        // 此时入参数minCapacity是1,以为在调用add方法的时候size+1了
        if (elementData == EMPTY_ELEMENTDATA) {
            // 就用DEFAULT_CAPACITY来作为最小的容量值10
            minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        // 再一次确定明确的容量
        ensureExplicitCapacity(minCapacity);
    }

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

        // overflow-conscious code
        // minCapacity为10,此时elementData还没有元素长度是0
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }
/**
     * 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
        // 从上面一路调用下来,minCapacity为10,elementData还是空的对象数组,oldCapacity为0
        int oldCapacity = elementData.length;
        // oldCapacity 的向右位移一位就是除以2的意思,newCapacity也为0
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        // 0 - 10 < 0成立
        if (newCapacity - minCapacity < 0)
            // newCapacity为10
            newCapacity = minCapacity;
        // MAX_ARRAY_SIZE是个啥玩意,请看下面解释
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            // 当想要申请的数组容量大小超过了最大的虚拟机允许的大小,
            // 就会重新计算出合适的
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        // 很显然这里我们没有超过,通常情况下minCapacity是比较接近size值的,
        // 那么接下来就是真正的给elementData缓存数组扩容,
        // Arrays.copyOf返回了一个复制好原来elementData内容的新的数组对象给elementData,
        // 对于我们这样从上门一直调用下来的情况elementData只是扩充了容量elementData.length变成了10,
        // 但是这个数组里面目前还没有元素,ArrayList的属性size还是为0,
        // 扩容完成后,我们再回过头来看上面add(E e)方法中:
        // elementData[size++] = e就很容易理解了,
        // 此处e只是添加到了elementData数组的第0个位置,
        // 然后size+1变成1,ArrayList.size()是1,
        // 表示里面真实的元素有1个,而非里面数组的长度是1。
        // 所以ArrayList的size和容量不一定是一样的,是不同的概念。
        elementData = Arrays.copyOf(elementData, newCapacity);
    }
public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        // newType我们就是Object[]的类类型,于是重新实例化了一个Object[]数组对象
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        // 并把传递进来的original就是elementData复制到新创建的copy数组对象里,
        // 这是一个jni的本地接口,因为数组的复制计算性能耗费高,
        // 所以Android工程师就采用了jni底层c/c++来更高效的执行复制操作,
        // 最后返回复制好的新创建的数组对象
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
    }
// 处理巨大容量的问题
private static int hugeCapacity(int minCapacity) {
        // 当前最小的容量小于0就抛出内存溢出错误
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        // 否则如果超过虚拟机允许的最大的数组大小,
        // 就使用Integer的最大值,反正使用Array的最大的值
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
    /**
     * The maximum size of array to allocate.
     * Some VMs reserve some header words in an array.
     * Attempts to allocate larger arrays may result in
     * OutOfMemoryError: Requested array size exceeds VM limit
     * Integer的最大值减去8 = 2147483647 - 8 = 2147483639
     * 这是数组能够申请最大的大小,如果试图申请比这个还要大的大小,
     * 就会超过VM虚拟机的限制而抛出内存溢出的错误OutOfMemoryError
     */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    ```
  - **删除**
  ```java

    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).
     *
     * @param index the index of the element to be removed
     * @return the element that was removed from the list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E remove(int index) {
        // 检查下需要删除的index会不会超过size大小,
        // 超过了虽然不一定会超出elementData的数组下标大小,
        // 当是木有元素内容啊,没有意义,
        // 而且数组删除内容是要移动元素位置的,容易出现问题,所以抛出了一个下标越界异常
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        // 操作计数加一
        modCount++;
        // 临时缓存下要被删除的元素对象
        E oldValue = (E) elementData[index];

        // 表示删除一个元素数组需要移动的个数
        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        // 缓存数组size-1的位置的引用置空,交给GC来管理内存
        elementData[--size] = null; // clear to let GC do its work
        // 返回被删除的元素对象
        return oldValue;
    }

(画的这么丑也好意思贴出来,真是变脸), ①、调用remove(1)方法时,index为1,如图假设我们ArrayList的容量是10,元素有5个即size为5。 ②、计算后,numMove为3。 ③、通过System.arraycopy来copy移动elementData数组,b为需要移动的元素,移动到a(也就是覆盖了index为1的值)。 ④、元素少了一个size减一,移动后elementData[4]的元素就没用了腾出来了,置为null后交给GC去处理内存。 最后返回被删除的旧元素对象。

**注意事项:**从上面可以看出,调用remove方法的时候,size是变动的,所以一下边遍历边删除就会出现问题:

边遍历边删除.png

执行结果
对应的值错乱了。**解决方案:**改用迭代器来删除。

// 删除集合中的指定的一个元素
public boolean remove(Object o) {
        // 当指定的元素为null时
        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;
    }
    ```
从上面源码可以看出,这个remove方法只是删除遍历的时候第一个与入参对象相等的元素,如下图所示:
  ![只删除最近的相等对象.png](http://upload-images.jianshu.io/upload_images/2971226-93785fe7a08ae37b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
> 注意事项:add了null的元素后,RecyclerView出现了空白项item的问题,所以数据在设置到适配器前得做非空检查
![add了null后.png](http://upload-images.jianshu.io/upload_images/2971226-3543b6ff939a2c58.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

  ```java
public void clear() {
        modCount++;

        // clear to let GC do its work
        for (int i = 0; i < size; i++)
            elementData[i] = null;

        size = 0;
    }

clear方法就很简单了,把遍历把缓存数组中有元素部分遍历置空,size也为0后交给GC处理。

  • 修改
public E set(int index, E element) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        // 保存修改前旧的元素对象
        E oldValue = (E) elementData[index];
        // 直接赋值修改index下标对应的缓存数组里的元素
        elementData[index] = element;
        // 返回修改前旧的元素对象
        return oldValue;
    }
    ```
- **查询**
```java
/**
     * Returns the element at the specified position in this list.
     * 返回指定位置的列表元素
    * 
     * @param  index index of the element to return 指定的位置
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc} 下标边界值异常
     */
    public E get(int index) {
        if (index >= size)
            throw new IndexOutOfBoundsException(outOfBoundsMsg(index));
        // 很简单直接获取缓存数组对应下标的元素对象
        return (E) elementData[index];
    }
    ```
通常我们查询遍历ArrayList的时候还会用到迭代器:
```java
Iterator<String> iterator = dataList.iterator();
while (iterator.hasNext()){
        String item = iterator.next();
        System.out.println("item_iterator = " + item);
}

来看看内部的实现:

private class Itr implements Iterator<E> {
        // The "limit" of this iterator. This is the size of the list at the time the
        // iterator was created. Adding & removing elements will invalidate the iteration
        // anyway (and cause next() to throw) so saving this value will guarantee that the
        // value of hasNext() remains stable and won't flap between true and false when elements
        // are added and removed from the list.
        protected int limit = ArrayList.this.size;

        // 游标值表示下一个元素的index下标
        int cursor;       // index of next element to return
        // 表示当前遍历到了哪一个元素的index下标,如果没有了就为-1
        int lastRet = -1; // index of last element returned; -1 if no such
        // 操作计数器
        int expectedModCount = modCount;

        public boolean hasNext() {
            // 如果下一个index小于当前具体的元素个数(初始值是集合的size,使用迭代器来add、remove元素的时候会被修改)表示集合中还有下一个元素返回true,否则为false
            return cursor < limit;
        }

        @SuppressWarnings("unchecked")
        public E next() {
            // 操作计数器不相等,抛出并发修改值异常(ArrayList是一个线程不安全的线性表,
            // 不同线程都操作一个ArrayList对象会出现线程同步问题)
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();
            // 临时存储游标值
            int i = cursor;
            // 如果游标值大于等于现有的元素个数,抛出没有此元素异常
            if (i >= limit)
                throw new NoSuchElementException();
            // 赋值给一个新的Object数组对象,避免全局的elementData被修改
            Object[] elementData = ArrayList.this.elementData;
            if (i >= elementData.length)
                throw new ConcurrentModificationException();
            // 游标值加一,便于下一次迭代器遍历使用
            cursor = i + 1;
            // 取出当前元素对象返回
            return (E) elementData[lastRet = i];
        }

        public void remove() {
            if (lastRet < 0)
                throw new IllegalStateException();
            if (modCount != expectedModCount)
                throw new ConcurrentModificationException();

            try {
                // 使用ArrayList的remove方法删除当前遍历位置的元素
                ArrayList.this.remove(lastRet);
                // 回退当前的游标值
                cursor = lastRet;
                // 当前遍历的元素已经被删除了index不存在则为-1
                lastRet = -1;
                expectedModCount = modCount;
                // 集合可被遍历的元素个数值减一
                limit--;
            } catch (IndexOutOfBoundsException ex) {
                // 删除元素的时候,当前遍历的元素大于等于集合的size则抛出异常,
                // 不过这里不太明白,为什么是抛出并发修改异常,
                // 估计是只有不同线程同时在做remove,
                // 或者add操作的时候由于size的变动而导致lastRet>=size的情况,
                // maybe暂且这么理解吧,希望有知道的小伙伴们告知留言
                throw new ConcurrentModificationException();
            }
        }
    }

三、总结

  1. ArrayList是线性表中的顺序存储结构的顺序表,因为内部维护的是一个数组,数组是一个拥有连续存储地址的存储块。
  2. ArrayList因为内部维护的是一个数组,查询和修改的效率很高,但是插入添加和删除的效率比较低,特别是数据量大的情况下比较明显。
  3. 在使用普通的for循环遍历ArrayList的时候删除其中的元素容易出现数据删除错乱问题,改用Iterator迭代器能够很好的解决这个问题。
  4. ArrayList在添加元素的时候是允许加入null元素的,为了避免后续使用数据时出现NullPointerException的异常,请先对要添加的元素做非空判断。
  5. ArrayList从上面的源码分析可以看出,它可以添加重复的元素对象,所以在添加对象的时候做好相等对象的判断。
    添加重复元素对象.png
  6. 从上面源码可以看出,ArrayList的size和真实申请的堆内存对象容量不同,所以在使用的时候控制好ArrayList的容量使用也是很好的性能优化手段。
  7. ArrayList的是线程不安全的,在多线程环境下需要注意对象数据同步问题。

结语

点击【Android高级工程师进阶学习】加入我们的圈子领取资料和我们一起吧学习交流吧!

  • Android进阶学习全套手册
    关于实战,我想每一个做开发的都有话要说,对于小白而言,缺乏实战经验是通病,那么除了在实际工作过程当中,我们如何去更了解实战方面的内容呢?实际上,我们很有必要去看一些实战相关的电子书。目前,我手头上整理到的电子书还算比较全面,HTTP、自定义view、c++、MVP、Android源码设计模式、Android开发艺术探索、Java并发编程的艺术、Android基于Glide的二次封装、Android内存优化——常见内存泄露及优化方案、.Java编程思想 (第4版)等高级技术都囊括其中。

  • Android高级架构师进阶知识体系图
    关于视频这块,我也是自己搜集了一些,都按照Android学习路线做了一个分类。按照Android学习路线一共有八个模块,其中视频都有对应,就是为了帮助大家系统的学习。接下来看一下导图和对应系统视频吧!!!

  • Android对标阿里P7学习视频

  • BATJ大厂Android高频面试题
    这个题库内容是比较多的,除了一些流行的热门技术面试题,如Kotlin,数据库,Java虚拟机面试题,数组,Framework ,混合跨平台开发,等

基于java各类数据结构的实现和各种排序 该文件里面包含基于java泛型各种数据结构的实现,如:单链表、双向链表、队列、二叉树等等,其中还包括各种排序算法的分析与实现。 立即下载

相关推荐

Android:ArrayList学习实例

本实例主要是对Android移动开发中的ArrayList的初步学习,涉及到HashMap的使用,以及为ArrayList添加监听器,还涉及到Toast的简单应用。

Android 开发也要懂得数据结构 - ArrayList源码

文章目录1.ArrayList特点2.ArrayList的继承关系3.ArrayList的常用方法3.1 创建初始化3.2 尾部插入 add(E e)3.3 中间插入 add(int index, E element)3.4 扩容 grow(int minCapacity)3.5 删除索引位置 remove(int index)3.6 删除指定元素 remove(Object o)3.7 修改元素 set(int index, E element)3.8 内容长度 size()3.9 判断是否为空 isEm

Good包籽的Android专栏 324

分布式光纤传感(DFOS)DTS/DAS/DSS 三合一:10公里管线监测实战与数据解读

本文详细介绍了分布式光纤传感(DFOS)技术在10公里管线监测中的实战应用,通过DTS(温度)、DAS(振动)、DSS(应变)三合一系统,实现对管线健康状态的立体感知。文章涵盖工程部署、数据采集、多物理量数据融合及噪声抑制等关键技术,展示了如何通过一根光纤完成复杂监测任务,显著提升管线安全性和维护效率。

weixin_29168153的博客 315

Android ArrayList★

1.ArrayList ArrayList的数据结构: 容量:CAPACITY ; 实际大小:size; ArrayList底层的数据结构就是数组,数组元素类型为Object类型,即可以存放所有类型数据。我们对ArrayList类的实例的所有的操作底层都是基于数组的。 2.ArrayList源码解析(JDK1.8) ArrayList底层是Object类型的数组elementData和数组的有效长度size。 //存放元素的数组 transient Object[] elementDat.

zenmela2011的专栏 4536

MobileNet V3 图像分类

MobileNet V3

Henry的博客 1771

Unity WebGL发布避坑指南:从内存设置到字体打包,一次搞定所有常见问题

本文详细解析Unity WebGL发布的完整流程,从内存设置到字体打包,提供全面的避坑指南。涵盖关键检查清单、内存与性能优化配置、资源处理专项优化及平台适配技巧,帮助开发者高效解决常见问题,确保项目顺利发布。

weixin_28693309的博客 148

Android面试——数据结构&算法

由(element)组成,并且是使用一块来存储。我们直接可以利用元素的索引(index)可以计算出该元素对应的存储地址。并且容量有限。

m0_37869471的博客 1201

3GPP协议解读_NTN系列(一)_38.811_非地面网络(NTN)的背景、应用场景和信道建模

非地面网络覆盖广,对物理攻击和自然灾害有一定的抵抗性。本文根据3GPP协议对NTN网络的背景、应用场景和信道模型进行了整理。

JCMLSY的博客 4932

android中数据结构,Android中的数据结构和算法

Android客户端面试基础(五)-数据结构与算法- http://blog.youkuaiyun.com/johnWcheung/article/details/72843223 数据结构:是指相互之间存在着一种或多种关系的数据元素的集合和该集合中数据元素之间的关系组成。算法:是特定问题求解步骤的描述,算法是独立存在的一种解决问题的方法和思想。算法时间复杂度和空间复杂度;>数据结构Android中的...

weixin_39757040的博客 679

大宗农产品交易知识图谱推理引擎的构建--需求分析

大宗农产品交易知识图谱推理引擎的构建 一、项目概述 ​ 进入信息时代,全球产生的数据量爆炸式增长,一方面数据产生的方式发生改变,由手工产生越来越多地转为自动化生成,另一方面,人类的活动也越来越依赖数据;民以食为天,粮食方面的信息数据对人类来说至关重要,而当前繁杂的数据已经超出了人工处理的范围,这就对数据采集和数据处理提出了新的要求。 知识图谱是将大量收集的数据整理成机器能处理的知识库,并实现可视化的展示。知识图谱本质上是一种大规模的语义网络,其主要目的是对真实世界里的实体或概念之间的关联关系进行描述;构造

qq_40583949的博客 2587

字节系,ali系,ks,pdd最新抓包方案

各大厂安卓逆向

qq_38759383的博客 1147

Android-从本质层面了解数据结构与算法

1.计算机存储单元与存储结构分析 2.算法与数据结构的关系 3.基础存储单元与连续存储单元 4.ArrayList与LinkedList结构分析 5.HashMap底层存储原理详解 6.Hash算法详解与Hash冲突 7.HashMap头插法与尾插法的优缺点 8.HashMap导致100%CPU解密

李木子的博客 1009

openclaw本地模型对接

使用是官方推荐的一种集成方式,它可以简化配置过程。但由于您的系统环境和之前复杂的配置历史,我为您梳理了一个核心流程,并增加了关键的“事后检查”步骤,以确保能从根本上解决问题。

suny8的专栏 2463

2024年安卓最新安卓开发者必看:Android的数据结构与算法——ArrayList源码解析,2024年最新2024吊打面试官系列

首先把传进来的collection集合转换成Object[]数组对象赋值给内部的数组缓存对象,然后初始化ArrayList的size大小,最后注释写c.toArray可能出错返回的不是Object[], 判断下如果返回的不是Object[]的类类型,就用Object[].class,复制一个Object[]类型的数组给elementData长度是size。只有系统,有方向的学习,才能在短时间内迅速提高自己的技术,只有不断地学习,不懈的努力才能拥有更好的技术,才能在互联网行业中立于不败之地。

2401_84556528的博客 389

【目标追踪】python背景模型减除法原理及其实现

python基于背景模型差法的视频目标追踪帧差法的问题:背景模型差法目标追踪原理1. 基本思路:2. 图例讲解:3. 存在的问题&如何解决:4. 最终效果预览第一步——调用摄像头:1. 使用opencv打开视频or摄像头:2. 读取逐帧图片:第二步——处理图片:1. 转换成灰度图:3. 累加权重重构背景:3. 计算像素差:3. 使用中值滤波和膨胀腐蚀去噪:3.1 中值滤波:3.2 图像腐蚀...

梁瑛平的博客 1948

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

android list存储数据结构,Android-常用数据结构List(ArrayList)----小总结(1),android-arraylist...

Android-常用数据结构List(ArrayList)----小总结(1),android-arraylist开发中,一个贴切的数据结构,可以非常好的满足需求的同时,最大程度的节省内存,这是一个精细的开发者必须要考虑的事情。在这里,稍微总结一下安卓开发中经常会使用到的一些数据结构,请大佬批评指正。1,数据结构与算法数据结构,表示一种数据模型,模型的元素之间存在着逻辑结构以及存储结构;算法表示一...

weixin_39610785的博客 717

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

Android的数据结构与算法----ArrayList源码解析

首先得明白ArrayList在数据结构中是个什么,从名字看,可以直译为“数组集合”,内部的实现八九不离十是用数组来实现的,因此在数据结构中属于线性表结构(0个或者多个元素的有限序列)

JerryloveEmily平 1564

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

ArrayList源码解析(jdk1.8)——思路篇(如何看源码)

前言:关于ArrayList相信大家都不陌生。而且大多数人应该都点开过它的源码浏览过。不过看到了什么,记住了什么,这是个值得深思的问题。博主今天写这篇文章的重点也不是解析其源码。更多的是想和大家分享一下看源码的一种方法以及一种思路。 源码解析第一步:简单了解其特性 ArrayList特点: ArrayList是有序的(放入顺序) ArrayList元素是不唯一的(可存放重复元素) ArrayList简介: ArrayList底层是由数组实现的 他的容量是动态增长的 操作元素时查询效率高,增删效

Gavin_Java_的博客 2991

小米2019秋招安卓B卷复盘:核心考点与原理深度解析

Android开发面试中,Activity启动模式、Handler消息机制、自定义View绘制流程始终是高频考点,其背后涉及的组件生命周期、内存优化与UI渲染原理,直接决定了应用的质量与稳定性。理解Handler内存泄漏需要从消息队列引用链与弱引用机制入手,而自定义View的MeasureSpec处理不当则会导致wrap_content失效。与此同时,随着设备形态多样化,多屏适配、安卓Launcher开发等场景成为新的工程挑战,要求开发者具备更全面的知识体系。以小米2019秋招安卓笔试题B卷为线索,系统梳理

weixin_34214500的博客 449

容器类源码解析系列(一) ArrayList 源码分析——基于最新Android9.0源码

ArrayList 源码分析——基于最新Android9.0源码 前言 ArrayList 既是开发人员在日常开发过程中经常会用到的数据处理容器,也是面试场景中经常会被问到的点。包括LinkedList,HashMap,SparseArray等。因此对这些个数据结构的源码,还是很有必要了解一下的。其他的几种容器,在后面的文章再做讲解。RT,本文主要讲解ArrayList。 要点 ArrayLis...

宇宝守护神(rainyang)的博客 731

行业寒冬:为什么有人说Android开发不再吃香?已拿offer_安卓开发工程师怎么变得很冷门了(1)

当然由于时间有限、能力也都有限,毕竟嵌入式全体系实在太庞大了,包括我那做嵌入式的同学,也不可能什么都懂,有些东西可能没覆盖到,不足之处,还希望小伙伴们一起交流补充,一起完善进步。只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。只要是程序员,不管是Java还是Android,如果不去阅读源码,只看API文档,那就只是停留于皮毛,这对我们知识体系的建立和完备以及实战技术的提升都是不利的。

2401_84132496的博客 936

顺丰科技Android秋招笔试客观题考点与真题解析

在安卓开发工程师的求职路上,笔试中的客观题往往是筛选人才的第一道关卡。这些题目看似基础,实则覆盖了计算机网络、操作系统、Java基础、Android四大组件与消息机制等核心知识体系。例如TCP三次握手的细节状态变化、死锁的预防与避免、Handler的消息循环机制等,都是考察开发者对底层原理理解深度的经典切入点。理解这些概念的基本原理,不仅有助于应对笔试中的选择题陷阱,更能为实际的工程实践打下坚实基础。从基础知识出发,结合典型真题进行拆解与复盘,能够帮助求职者建立清晰的知识边界感,有效提升在安卓开发岗位校招和

weixin_30457551的博客 340

Android知识点整理17:ArrayList

源码主要基于android-30 ArrayList 一、构造方法 1、默认构造 /** * 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. */ pr

千寻 294
上一篇: 2020Android开发前景如何?在互联网摸爬滚打12年要是打算跳槽该往哪方面发展?值得一读!
下一篇: Android:这是一份全面 & 详细的Retrofit 2.0 源码分析指南
Android725
博客等级 码龄7年 1708粉丝 350原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值