java学习_part01_java核心卷_day05_ArrayList

1. 底层数据结构

  • ArrayList是List接口的可调整大小的数组实现

  • 增删慢:每次增删数据,需要拷贝以及移动元素位置

  • 查询快:数组内存是一块连续空间,可以根据索引方式获取对应位置元素

 

2. 实现与继承

2.1 Serializable接口

序列化接口,没有方法或字段,仅用于标识,实现该接口才能实现序列化反序列化

  • 序列化:将对象的数据转换成字节序列写入文件

  • 反序列化:将文件中的字节序列数据恢复出来

  • 序列版本号:

    • 序列版本号是序列化前后唯一标识符号

    • 如果没有人为指定序列版本号,编译器会自动添加

    • 反序列化时,JVM会把字节流中的序列版本号与被序列化类中的序列版本号进行比对,一致才会进行反序列化,否则报错

    • 建议实现该接口后人为写序列版本号(或自动添加)

    • static修饰部分不会被序列化:因为序列化保存的是对象的状态,与类无关

    • transient修饰部分不会被序列化:希望某些字段不被序列化(如密码),该字段反序列化结果为null

 

2.2 Cloneable接口

克隆接口

  • 被克隆对象的类必须实现克隆接口

  • 重写clone方法

  • 浅拷贝通过重写clone方法实现

  • 深拷贝推荐使用序列化方式实现

 

2.3 RandomAccess接口

快速随机访问接口,允许算法更改其行为,以便应用于随机访问列表或顺序访问列表时提供良好的性能

  • 实现了该接口的List,则使用普通for循环随机访问,ArrayList

  • 没有实现该接口的List,则使用增强for循环或迭代器进行顺序访问,LinkedList

 

2.4 AbstractList抽象类

List接口的骨架实现,ArrayList,LinkedList都是其子类

 

 

3. 源码分析

3.1 构造方法

  • ArrayList():构造初始容量为10的空列表

  • ArrayList(Collection<? extends E> c):构造一个包含指定集合元素的列表,按照他们由集合的迭代器返回的顺序

  • ArrayList(int initialCapacity):构造具有指定初始容量的空列表

 

3.2 添加方法

  1. public boolean add(E, e):指定元素添加到列表末尾

    • 扩容:扩容为原来的1.5倍

     

  2. public void add(int index, E, element):指定位置添加元素

    • 指定位置添加:指定位置后元素先后移,指定位置再添加元素

     

  3. public boolean addAll(Collection<? extends E> c):c中元素追加到列表末尾,按照c迭代器返回顺序添加

     

  4. public boolean addAll(int index, Collection<? extends E> c):c中元素添加到指定位置

 

3.3 迭代器

public Iterator<E> iterator():以正确顺序返回该列表中元素的迭代器

 

集合的迭代器接口public interface Iterator<E>

方法 说明
default void forEachRemaining(Consumer<? super E> action) 对每个元素进行某种操作
boolean hasNext()  
E next()  
default void remove() 从集合中删除此迭代器返回的最后一个元素

 

补充:

可迭代接口public interface Iterable<E>,实现了该接口的对象可以使用增强for循环

方法 说明
default void forEach(Consumer <? super T> action) 对每个元素执行操作
Iterator<T> iterator() 返回T元素的迭代器

 

3.4 其他方法

 

4. 常见面试题

4.1 如何扩容

构建新数组,新数组大小为原数组的1.5倍,原数组元素复制进入新数组

 

4.2 频繁扩容导致添加性能急剧下降,如何解决

通过指定初始容量初始化数组

 

4.3 插入删除元素一定慢吗

取决于元素离数组末端距离,不一定每次插入都需要构建新数组,因此不一定比LinkedList慢

 

4.4 线程安全问题

ArrayList非线程安全,线程安全版本为Vector.

 

4.5 和LInkedList区别

问:ArrayList,LinkedList哪个更占空间?

答:

  • 表面上LInkedList更占空间(包括前索引,后索引)

  • 实际上如果ArrayList添加元素超过数组大小时,需要扩容为1.5倍,如果只添加一个元素则会有较大的空间浪费,因此ArrayList不一定比LinkedList节省空间.

  • ArrayList中elementData表示底层数组,默认10,用transient修饰,size表示数组中元素个数.ArrayList重写了writeObject方法,序列化时候不会把elementData数组完全序列化,只序列化elementData中的前size个元素,空值不会序列化.

2. 实现与继承

2.1 Serializable接口

序列化接口,没有方法或字段,仅用于标识,实现该接口才能实现序列化反序列化

  • 序列化:将对象的数据转换成字节序列写入文件
  • 反序列化:将文件中的字节序列数据恢复出来
  • 序列版本号:
    • 序列版本号是序列化前后唯一标识符号
    • 如果没有人为指定序列版本号,编译器会自动添加
    • 反序列化时,JVM会把字节流中的序列版本号与被序列化类中的序列版本号进行比对,一致才会进行反序列化,否则报错
    • 建议实现该接口后人为写序列版本号(或自动添加)
    • static修饰部分不会被序列化:因为序列化保存的是对象的状态,与类无关
    • transient修饰部分不会被序列化:希望某些字段不被序列化(如密码),该字段反序列化结果为null

2.2 Cloneable接口

克隆接口

  • 被克隆对象的类必须实现克隆接口
  • 重写clone方法
  • 浅拷贝通过重写clone方法实现
  • 深拷贝推荐使用序列化方式实现

2.3 RandomAccess接口

快速随机访问接口,允许算法更改其行为,以便应用于随机访问列表顺序访问列表时提供良好的性能

  • 实现了该接口的List,则使用普通for循环随机访问,ArrayList
  • 没有实现该接口的List,则使用增强for循环或迭代器进行顺序访问,LinkedList

2.4 AbstractList抽象类

List接口的骨架实现,ArrayList,LinkedList都是其子类

3. 源码分析

3.1 构造方法

  • ArrayList():构造初始容量为10的空列表
  • ArrayList(Collection<? extends E> c):构造一个包含指定集合元素的列表,按照他们由集合的迭代器返回的顺序
  • ArrayList(int initialCapacity):构造具有指定初始容量的空列表

3.2 添加方法

  1. public boolean add(E, e):指定元素添加到列表末尾

    • 扩容:扩容为原来的1.5倍
  2. public void add(int index, E, element):指定位置添加元素

    • 指定位置添加:指定位置后元素先后移,指定位置再添加元素
  3. public boolean addAll(Collection<? extends E> c):c中元素追加到列表末尾,按照c迭代器返回顺序添加

  4. public boolean addAll(int index, Collection<? extends E> c):c中元素添加到指定位置

3.3 迭代器

public Iterator iterator():以正确顺序返回该列表中元素的迭代器

集合的迭代器接口public interface Iterator

方法 说明
default void forEachRemaining(Consumer<? super E> action) 对每个元素进行某种操作
boolean hasNext()
E next()
default void remove() 从集合中删除此迭代器返回的最后一个元素

补充:

可迭代接口public interface Iterable,实现了该接口的对象可以使用增强for循环

方法 说明
default void forEach(Consumer <? super T> action) 对每个元素执行操作
Iterator iterator() 返回T元素的迭代器

3.4 其他方法

4. 常见面试题

4.1 如何扩容

构建新数组,新数组大小为原数组的1.5倍,原数组元素复制进入新数组

4.2 频繁扩容导致添加性能急剧下降,如何解决

通过指定初始容量初始化数组

4.3 插入删除元素一定慢吗

取决于元素离数组末端距离,不一定每次插入都需要构建新数组,因此不一定比LinkedList慢

4.4 线程安全问题

ArrayList非线程安全,线程安全版本为Vector.

4.5 和LInkedList区别

问:ArrayList,LinkedList哪个更占空间?

答:

  • 表面上LinkedList更占空间(包括前索引,后索引)
  • 实际上如果ArrayList添加元素超过数组大小时,需要扩容为1.5倍,如果只添加一个元素则会有较大的空间浪费,因此ArrayList不一定比LinkedList节省空间.
  • ArrayList中elementData表示底层数组,默认10,用transient修饰,size表示数组中元素个数.ArrayList重写了writeObject方法,序列化时候不会把elementData数组完全序列化,只序列化elementData中的前size个元素,空值不会序列化.

4.6 如何复制一个ArrayList到另一个ArrayList

  • clone()方法
  • ArrayList构造方法
  • addAll方法-p"> 

4.6 如何复制一个ArrayList到另一个ArrayList

  • clone()方法

  • ArrayList构造方法

  • addAll方法

 

上一篇:从入门到入土:Python爬虫学习|Selenium自动化模块学习|简单入门|轻松上手|自动操作浏览器进行处理|chrome|PART01


下一篇:OAuth 2.0 Server PHP实现示例