stronglzq

2020-10-20        longzqa@163.com        stronglzq

【摘要】针对数组容量固定无法扩展的问题,引入数组列表(ArrayList)。主要对数组列表的声明及基本操作等内容进行介绍,基本操作包括增加元素、插入元素、删除元素以及元素的访问与修改。

  • 为什么要引入数组列表(ArrayList)
  • 数组列表容量为什么能变动
  • 如何声明数组列表
  • 数组列表的增加、插入、删除、修改、访问操作
  • 数组列表的缺陷
  • 如何灵活的扩展数组,又能方便的访问元素
  • 如何降低数组列表的内存消耗 -- 预设列表容量

为什么要引入数组列表(ArrayList)

数组在创建后容量固定,而实际解决问题的过程中,元素的数量是变动的,此时采用数组来存储数据难以满足业务需求,因此引入数组列表。

数组列表容量为什么能变动

在创建数组时,需确定数组长度,此时数组中产生一个个“萝卜坑”(有初始值,若为int类元素,初始值为0),增加元素即为往“萝卜坑”中放入“萝卜”;数组列表可在声明时预估容量,或不预估容量,当不预估容量,或者元素超过预估容量时,若增加一个元素,则会自动申请一个新的数组,将原先数组列表的内容复制到新数组中,并在末端放入新元素。

如何声明数组列表

数组列表是具有类型参数(type parameter)的泛型类(genetic class),故需要在声明数组列表时,指明元素类型,语法为ArrayList<element type>。数组列表的声明语法有三种:

  • ArrayList<element type> name = new ArrayList<element type>();
  • ArrayList<element type> name = new ArrayList<>();,相对于第一种声明方法,省略了等号右侧数组列表的元素类型;
  • var name = new ArrayList<element type>();使用var则一定不能省略等号右侧数组列表的元素类型。
public class Person{
	private String name;
	private int age;
	
	public Person(String name, int age){
		this.name = name;
		this.age = age;
	}
}

public class ArrayListTest{
	// 用数组列表来存储Person数据
	var person = new ArrayList<Person>();
	// ArrayList<Person> person = new ArrayList<Person>();
	// ArrayList<Person> person = new ArrayList<>();
	person.add(new Person("Peter", 20));
	person.add(new Person("Tom", 23));
	person.add(new Person("Lucy", 26));
}

数组列表的增加、插入、删除、修改、访问

(1)数组列表的增加为在列表末端增加元素,使用add()方法;(2)对位置i的元素修改为e,语句为set(i, e);(3)访问位置i的元素,语句为get(i);(4)在位置i,插入元素e,则原先位置i及之后的元素均向后移一位,语句为add(i, e);(5)删除位置i的元素,语句为remove(i)

注:数组列表的插入、删除效率低。

public ArrayListTest{
	// 用数组列表来存储Person数据
	var person = new ArrayList<Person>();
	// ArrayList<Person> person = new ArrayList<Person>();
	// ArrayList<Person> person = new ArrayList<>();
	person.add(new Person("Peter", 20));
	person.add(new Person("Tom", 23));
	person.add(new Person("Lucy", 26));
	
	// 修改元素
	person.set(1, new Person("Peter Long", 25));
	// 插入元素
	person.add(2, new Person("Jack", 30));
	// 删除元素
	person.remove(0);
	// 访问元素
	person.get(1);
}

数组列表的缺陷

使用数组列表存在两个缺陷,(1)无法直接通过元素下标来访问元素,不方便;(2)数组列表由于每变动一个元素,均需要重新申请一个新的数组来存放,对内存消耗大;(3)数组列表元素的插入、删除效率低,解决方案为采用链表的数据类型;

如何既灵活的扩展数组,又能方便的访问数组元素?

数组无法灵活的扩展,故引入了数组列表,但数组列表元素访问繁琐,针对各自的问题,有一解决方法:(1)创建一个数组列表,并填充元素;(2)创建一个数组,数组大小为数组列表实际元素的数量;(3)使用toArray方法,将数组列表的元素复制到该数组中。

public class ArrayListTest{
	// 用数组列表来存储Person数据
	var person = new ArrayList<Person>();
	// ArrayList<Person> person = new ArrayList<Person>();
	// ArrayList<Person> person = new ArrayList<>();
	person.add(new Person("Peter", 20));
	person.add(new Person("Tom", 23));
	person.add(new Person("Lucy", 26));
	
	// 创建一个数组,大小为数组列表的大小
	Person[] personArray = new Person[person.size()];
	// 将数组列表的元素复制到数组中
	person.toArray(personArray);
}

注:数组列表的size()方法返回数组列表实际元素的数量,而数组的size()方法返回数组容量。

如何降低数组列表的内存消耗?-- 预设列表容量

针对数组列表内存消耗大的问题,可以预设一个列表容量,在元素数量不超过预设容量时,元素的增加不需要重新分配空间。预设列表容量有两种方式:(1)在构造数组列表时,确定列表容量;(2)使用数组列表的ensureCapcity()方法。

public class ArrayListTest{
	// 预设数组列表的容量为100
	var person = new ArrayList<Person>(100);
	// 或 var person = new ArrayList<Person>();  person.ensureCapcity(100);
}

相关文章: