List 集合总结(ArrayList源码调试)

目录

                  ArrayList 类的架构图

ArrayList对外提供的成员参数

下面是对ArrayList源码的调试

1.创建不指定初始化大小的构造器ArrayList对象底层的创建过程:

2.向集合中插入一个元素:

 3.获取一个元素

4.删除一个元素 指定索引

5.删除指定的元素

6.迭代器

总结

 扩展


   ArrayList 类的架构图

ArrayList对外提供的成员参数

private static final int DEFAULT_CAPACITY = 10;  //如果没有指定数组的初始化容量,默认是10个
private static final Object[] EMPTY_ELEMENTDATA = {}; //用来初始化保存元素的数组(下面用不默认表示)
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}; //用来初始化保存元素的数组(下面用默认表示)
transient Object[] elementData; //定义保存元素的数组
private int size; //ArrayList的大小(它包含的元素数)

ArrayList对外提供了三个构造参数:

public ArrayList(int initialCapacity)       //指定初始化数组的大小
public ArrayList()                          //不指定初始化的大小
public ArrayList(Collection<? extends E> c) //指定一个集合类型

下面是对ArrayList源码的调试

public class TestArrayList {
    public static void main(String[] args) {
        //创建一个ArrayList对象
        List<String> list = new ArrayList<>();
        //添加一个元素
        list.add("0");
        //将元素添加到指定的索引
        list.add(1,"1");
        //获取一个元素
        String s = list.get(0);
        //删除一个元素 指定索引
        list.remove(1);
        //删除指定的元素
        list.remove("2");

    }
}

1.创建不指定初始化大小的构造器ArrayList对象底层的创建过程:

    List<String> list = new ArrayList<>();

   

   调用不指定初始化容量构造器的时候,初始化保存元素对象数组是用  默认  的数组。

2.向集合中插入一个元素:

list.add("0");

2.1调用到add方法,在add方法中调用  ensureCapacityInternal(size + 1) (容量内部计数方法)size+ 1是为了判断当前数组的长度是否可以存储这个元素,如果不可以会调用grow(minCapacity)方法进行容量的扩增,如果可以直接将插入的元素保存到当前已经存放元素的下一个位置。
下面这个地方就是判断下一个存储的数据,是否>数组设置的容量,如果>调用grow方法进行扩容。

下面这个方法就是ArrayList进行扩容的方法。

包括add("index","2")也是同样的逻辑,只是在复制当前数组的时候把指定的index位置空出来,留给添加指定的元素。

 3.获取一个元素

4.删除一个元素 指定索引

删除一个元素就是将指定删除的位置全部向前面移动一位。并将最后一个索引设置为null。

5.删除指定的元素

删除指定的索引会进行遍历整个集合。当找到这个元素的索引后,和删除指定的索引一样。

6.迭代器

迭代器Itr类是ArrayList中的私有类保证了封装性,只能通过一个公共方法去获取Itr的实例,进行调用。

总结

  上面我们写了这么一大篇,是时候该来总结总结一下了

  1.查询高效、但增删低效,增加元素如果导致扩容,会将所有的元素进行复制,删除元素一定会复制。增加和删除操作会导致元素复制,因此,增删都相对低效。ArrayList底层是一个数组,天然自带索引,查询操作相当于在操作指定的索引,所以查询操作是高效的,且增加操作只有在列表加载更多时才会用到 ,而且是在列表尾部插入,所以也不需要移动数据的操作。而删操作则更低频。 故选用ArrayList作为保存数据的结构

  2.线程不安全,api操作不是原子性操作,当有多个线程同时执行后产生竞态条件。所以不是线程安全的操作。

 扩展

       1.transient 关键字有什么用?(transient关键字和序列化有直接的关系)

         在ArrayList中的elementData这个数组的长度是变长的,java在扩容的时候,有一个扩容因子,也就是说这个数组的长度是大于等于ArrayList的长度的,我们不希望在序列化的时候将其中的空元素也序列化到磁盘中去,所以需要手动的序列化数组对象,所以使用了transient来禁止自动序列化这个数组,但是会序列化元素中的数据,而不是数组。

        2.什么是序列化?

        序列化就是可以很方便的保存内存中java对象的状态,同时也为了方便传输。 

        序列化时需要注意事项

        序列化时最好是定义序列化版本id  即 public  static  final  Long  seriaVersionUID  =  1L (默认)  或者 xxxxx L(自定义64位行)

        因为反序列化会判断序列化中的id和类中的id是否一样,如果不定义虽然会自动生成,但如果后面改了东西列,所以还是自觉点定义一个id,省去好多麻烦

        同时记住静态变量不会被序列化的,它可不在堆内存中,序列化只会序列化堆内存

        3.ArrayList实现Cloneable接口的意义?

           实现这个方法,我觉得就是为了调用clone方法的时候不报异常,实际上clone方法是一个浅度复制,只保存了元素的引用,没有保存元素的本身。

          

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值