Java核心技术第5章(4)

5.3 泛型数组列表

    在许多程序设计语言中,特别是在C语言中,必须在编译时就确定整个数组的大小.这样必须在初始化时就确定数组大小.在 Java中,情况就好多了,它 允许在运行时确定数组的大小.
int actualSize = ...;
Employee[] staff = new Employee[actualSize];
    这段代码并没有完全解决运行时动态更改数组的问题.一旦确定了数组的大小,改变它就不太容易了.在Java中,解决这个问题最简单的办法就是使用Java中另外一个被称为 ArrayList的类.它使用起来有点像数组,但在添加或删除元素时,具有自动调节数组容量的功能.
    ArrayList是一个采用类型参数的泛型类. 为了指定数组列表保存的元素对象类型,需要用一对尖括号将类名括起来加载后面.例如,ArrayList<Employee> .
    下面声明和构造一个保存Employee对象的数组列表:
ArrayList<Employee> staff = new ArrayList<Employee>();
    两边都使用类型参数Employee,可以省去右边的类型参数:
ArrayList<Employee> staff = new ArrayList<>();
    这被称为"菱形"语法,因为空尖括号<>就像一个菱形. 可以结合 new 操作符使用菱形语法.编译器会检查新值是什么,如果赋值给一个变量,或传递到某个方法,或者从某个方法返回,编译器会检查这个变量,参数或方法的泛型类型,然后将这个类型放在<>中.在这个例子中,new ArrayList<>()将赋一个类型为ArrayList<Employee>的变量,所以泛型类型为Employee .
    使用add方法可以将元素添加到数组列表中.数组列表管理着对象引用的一个内部数组.最终,数组的全部空间有可能被用尽,这就显现出数组列表的操作魅力: 如果调用add且内部数组已经满了,数组列表将自动地创建一个更大的数组,并将所有的对象从较小的数组中拷贝到较大的数组中.
    如果已经清楚或估计出数组可能存储的元素数量,就可以在填充数组之前调用ensureCapacity方法:
staff.ensureCapacity(100);
    这个方法调用将分配一个包含100个对象的内部数组,然后调用100次add,而不用重新分配空间.
    另外,还可以把初始容量传递给ArrayList构造器:
ArrayList<Employee> staff = new ArrayList<>(100);
    警告:分配数组列表,如下所示:
new ArrayList<>(100);       // capacity is 100
    它与为新数组分配空间有所不同:
new Employee[100];          // size is 100
    数组列表的容量与数组的大小有一个非常重要的区别.如果为数组分配100个元素的存储空间,数组就有100个空位置可以使用,而容量为100个元素的数组列表只是 拥有保存100个元素的潜力(实际上,重新分配空间的话,将会超过100),但是在最初,甚至完成初始化构造之后,数组列表根本就不含有任何元素.
    size方法将返回数组列表中包含的实际元素数目.例如
staff.size();
    将返回staff数组列表的当前元素数量,它等价于数组a的a.length .
    一旦能够 确认数组列表的大小不再发生变化,就可以调用trimToSize方法,这个方法将存储区域的大小调整为当前元素数量所需要的存储空间数目. 垃圾回收器将回收多余的存储空间.
    一旦整理了数组列表的大小,添加新元素就需要花费时间再次移动存储块,所以应该在确认不会添加任何元素时,再调用trimToSize .
    注释:ArrayList类似于C++的vector模板,ArrayList与vector都是泛型类型.但C++的vector模板为了便于访问元素重载了[]运算符.由于 Java没有运算符重载,所以必须调用显式的方法.此外, C++的vector是值拷贝.例如a和b,赋值操作a=b将会构造出一个与b长度相同的新向量a,并将所有的元素由b拷贝到a,而在 Java中,这条赋值语句的操作结果就是让a和b 引用同一个数组列表.
    java.util.ArrayList<T>的方法如下:
ArrayList<T>()
    构造一个空数组列表
ArrayList<T>(int initialCapacity)
    用指定容量构造一个空数组列表
boolean add(T obj)
    在数组列表的尾端添加一个元素,永远返回 true
int size()
    返回存储在数组列表中的当前元素数量(这个值小于等于数组列表的容量)
void ensureCapacity(int capacity)
    确保数组列表在不重新分配存储空间的情况下就能够保存给定数量的元素
void trimToSize()
    将数组列表的存储容量削减到当前尺寸

5.3.1   访问数组列表元素

    数组列表自动扩展容量的便利增加了访问元素语法的复杂程度,ArrayList类并不是Java程序设计语言的一部分,它只是标准程序库中的一个使用类.
    使用get和set实现访问或改变数组元素的操作,而不是[]语法格式.
staff.set(i, harry);
    它等价于对数组a的元素赋值(数组的下标从0开始)
a[i] = harry;
    使用add方法为数组添加新元素,而不要使用set方法,它只能替换数组中已经存在的元素内容.
    使用下列格式获取数组列表的元素:
Employee e = staff.get(i);
    等价于
Employee e = a[i];
    下面这个技巧既可以灵活地扩展数组,又可以方便地访问数组元素.首先,创建一个数组,并添加所有的元素.
ArrayList<X> list = new ArrayList<>();
while(...)
{
    x = ...;
    list.add(x);
}
    执行完上述操作后, 使用toArray方法将数组列表的元素拷贝到一个数组中.
X[] a = new X[list.size()];
list.toArray(a);
    除了在数组列表的尾部追加元素之外,还可以在数组列表的中间插入元素,使用带索引参数的add方法.
int n = staff.size() / 2;
staff.add(n, e);
    为了插入一个新元素,位于n之后的所有元素都要向后移动一个位置,如果插入新元素后,数组列表的大小超过了容量,数组列表就会被重新分配存储空间.
    同样地,可以从数组列表中间删除一个元素.
Employee e = staff.remove(n);
    位于这个位置之后的所有元素都向前移动一个位置,并且数组的大小减1 .
    对数组实施插入和删除元素怒的操作效率比较低,如果经常需要插入,删除元素,就应该考虑链表了.
    可以用 for each 训话遍历数组列表:
for (Employee e : staff)
    do something with e
    这个循环和下列代码具有相同的效果
for (int i = 0; i < staff.size(); i++)
{
    Employee e = staff.get(i);
    do something with e;
}
    程序5-11对第4章中的EmployeeTest做出修改,将Employee[]数组替换成了ArrayList<Employee>.请注意下面的变化:
    不必指出数组的大小
    使用add将任意多的元素添加到数组中
    使用size()替代length计算元素的个数
    使用e.get(i)替代a[i]访问元素
    arrayList/ArrayListTest.java如下所示:
package arrayList;
import java.util.*;

public class ArrayListTest
{
    public static void main(String[] args)
    {
        // fill the staff arrayl list with three Employee objects
        ArrayList<Employee> staff = new ArrayList<>();
        staff.add(new Employee("Carl", 75000, 1999, 1, 20));
        staff.add(new Employee("harry", 57000, 1999, 1, 2));
        staff.add(new Employee("Tony", 50000, 1999, 2, 20));

        // raise everyone's salary by 5%
        for (Employee e : staff)
            e.raiseSalary(5);

        // print out information about all Employee object
        for (Employee e : staff)
            System.out.println("name = " + e.getName() + ", salary = " + e.getSalary() + ", hireDay = " + e.getHireDay());
    }
}
    运行结果如下所示:

    java.util.ArrayList<T>方法如下:
void set(int index, T obj)
    设置数组列表指定位置的元素值,这个操作将覆盖这个位置的原有内容
T get(int index)
    获得指定位置的元素值
void add(int index, T obj)
    向后移动元素,以便插入元素
T remove(int index)
    删除一个元素,并将后面的元素向前移动,被删除的元素由返回值返回

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值