在java中允许数组大小在运行过程中进行确定,通过arrayList的类来实现,这个类使用起来有点像数组,但在添加或者删除元素的时候,具有自动调节数组容量的功能,而不需要谓词编写代码。
ArrayList是一个采用类型参数type parameter的泛型类(generic class),为了指定数组列表保存咋元素的对象类型,需要用一堆尖括号将类名括起来加在后面。例如ArrayLIst。这种语法被称为“菱形语法”,因为尖括号就像是一个菱形,可以结合new操作符使用菱形语法,编译器会检查这个比那领、参数或者是方法的泛型类型,然后将这个类型放在<>中,在这个例子中,new ArrayLIst<>()将会赋值一个类型是ArrayList的变量,所以泛型类型为Employee。
数组列表管理着对象引用的一个内部数组。最终,数组的全部空间有可能被用尽,这就展现出数组的魅力:如果调用add且内部数组已经满了,数组列表就会自动创建一个更大的数组,并将所有的数组拷贝到较大的数组中。
如果已经清楚或者能够预估出来数组的需要存储的元素,可以在其填充数组之前调用ensureCapacity方法,分配一个固定大小的内部数组,然后调用100次add,而不用重新分配空间,除此之外,还可以把初始容量传递给ArrayList构造器:
ArrayList staff = new ArrayList<>(100);
注意📢:
分配数组列表,如:new ArrayList<>(100) // capacity is 100
它与新数组分配空间有所不同:new Employee[100] //size is 100
数组列表的容量与数组的大小有一个非常重要的区别。如果为数组分配一个100个元素的存储空间,数组就有100个空位置可以用。而容量为100个元素的数组列表只是拥有保存100个元素的潜力,实际上,重新分配空间的话,将会超过100个,但是再最初,甚至完成初始化构造之后,数组列表根本就不含有任何元素。
访问数组列表元素:
数组列表自动扩容的遍历增加了访问元素语法的复杂度,其原因是ArrayList类并不是Java程序设计语言的一部分,它只是一个由某些人编写并放入标准库的一个实用类。
使用get和set方法实现访问或者改变数组元素的操作,而不能使用[]语法格式
数组中插入元素
在数组中插入元素,可以县创建一个数组,然后往里面添加所有元素,然后使用toArray方法将数组元素拷贝到一个数组中。除了在数组列表的尾部追加以外,还可以在数组列表的中间插入元素,使用带索引参数的add方法。为了插入一个新元素,例如在数组的第n位插入一个元素,位于n位之后的所有元素都要像后面移动一位,如果插入新元素后,数组列表的大小超过了容量,数组列表就会被重新分配存储空间。
数组中删除元素
同样,可以对数组中的元素进行删除操作,如果从n位置删除一个元素,位于这个元素之后的元素都需要前移一位,并且数组的大小减1.对于数组实施插入和删除元素的操作效率比较低。对于小型数组来说,这一点不必担心,但是如果数组的存储元素比较多,又要经常在中间位置插入、删除元素,就应该考虑使用链表了,可以使用“for each”循环遍历数组别表。
把Employee[] 替换成了ArrayList 数组变化
- 不必指出数组的大小
- 使用add将任意多的元素添加到数组中
- 使用size()替代length计算元素的数量
- 使用a.get(i)替代a[i]访问元素
代码demo如下:
package corejava.chapter5;
import corejava.chapter5.extendsPackage.Employee;
import java.util.ArrayList;
/**
* @Auther WangYu
* @Date 2022/3/6
* 数组的测试类
*/
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<Employee> staff = new ArrayList<>();
staff.add(new Employee("CC", 2000, 2022, 12, 12));
staff.add(new Employee("DD", 3000, 2022, 12, 12));
staff.add(new Employee("EE", 4000, 2022, 12, 12));
for (Employee employee : staff) {
employee.raiseSalary(200);
}
for (Employee employee : staff) {
System.out.println("name = " + employee.getName() + "salary" + employee.getSalary() + "hireDay:" + employee.getHireDay());
}
}
}
对象的自动拆箱与自动装箱
有时候,需要将int这样的基本类型转化为对象,所有的基本类型都有一个与之对应的包装类型,例如,Integer类对应的基本类型为int。通常,这些类被称为包装器wrapper,这些独享包装器类拥有很明显的名字。对象包装器类是不可以变的,即一旦构造了包装器,就不允许更改包装在其中的值。同时,对象包装器还是final,因此不能定义它们的子类。
假设想定义个整形数组列表,而尖括号中的类型参数不允许是基本类型,也就是说不能写成ArrayList,这里就是用到了Integer类型的这种包装类。可以声明为一个Interger类型的数组列表:ArrayList list = new ArrayList<>;
注意:由于每个值分别包装在独享中,所以ArrayList的效率远远小于int[]数组,因此,应该用它来构建小型集合,其原因是此时程序员操作的方便性要比执行效率更加重要。
自动装箱要求boolean、byte、char <=127,介于-128~127之间的short和int也被包装在固定的对象中,例如,如果在前面的例子中将a和b初始化为100,它们进行比较的结果一定成立。
关于自动装箱的说明:
- 由于自动包装器引用可以为null,所以自动装箱可能会抛出一个NUllPointerException,这时候需要对可能为空的情况进行特殊处理,避免这种NPE出现。
- 如果在一个表达式中混合使用Integer好Double类型,Integer值就会拆箱,提升为double,再装箱成为Double。
- 拆箱和装箱是编译器人可以的,而不是虚拟机,编译器在生成类的字节码时候,插入必要的方法调用。虚拟机只是执行这些字节码而已。
- 使用数值对象包装器的好处是,可以将某些基本方法防止在包装器中,例如,讲一个数组字符串转化成数值。
要想让一个字符串转化成为一个整形,可以用下面这种方式:
int x -= Integer.parseInt(str);
这里与Integer类型对象没有任何关系,parseInt是一种静态方法,但是Integer类是放置这个方法的一个好地方。
包装器不可以修改数组参数
有些人认为包装器可以用来实现数组参数的修改,这种理解是错误的,在java中方法都是值传递,所以不可能编写一个能够增加整形参数值的方法。