Java顺序表(2)

发布时间:2024年01月17日

🐵本篇文章将对ArrayList类进行讲解



一、ArrayList类介绍

上篇文章我们对顺序表的增删查改等方法进行了模拟实现,实际上Java提供了ArrayList类,而在这个类中就包含了顺序表的一系列方法,这样在用顺序表解决问题时就不用每次都去实现它的方法了

再ArrayList类中有下面几个字段:

上述字段会在下面的解释中进行讲解

二、ArrayList的构造方法

ArrayList的构造方法一共有三种

2.1 第一种构造方法

上述代码中,先定义了数组EMPTY_ELEMENTDATA,该数组为空,之后又定义了数组elementData,接下来红色框部分的就是构造方法,该方法有一个参数initialCapacity(即顺序表的初始容量),当initialCapacity > 0时,为elementData分配了长度为initialCapacity大小的空间,当initialCapacity =?0时,将elementData赋值为EMPTY_ELEMENTDATA,也就是此时elementData为空数组,即顺序表现在为空,若initialCapacity为负数,则抛出异常

总结:该构造方法就是给顺序表分配空间的

ArrayList<Integer> arrayList = new ArrayList<>(5); //此时顺序表的长度为5
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);

2.2 第二种构造方法

可以看到此时elementData为一个空数组,那么看下面的代码

ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);

构造方法并没有给顺序表分配空间,为什么此代码编译运行都没有问题?下面通过源码进行解释,首先不带参的构造方法确实没有给顺序表分配空间,那么没有报错的原因只可能是在add方法上

add方法中调用了ensureCapacityInternal方法:

在该方法中调用了ensureExplicitCapacity方法,其参数为calculateCapacity方法的返回值,该方法的参数分别为elementData数组和minCapacity先看calculateCapacity方法:

上述代码中的DEFAULT_CAPACITY是默认容量:10,minCapacity为1,所以这里将10作为该方法的返回值并作为ensureExplicitCapacity的参数,再去看ensureExplicitCapacity方法:

接下来看grow方法:

总结:

1.对于空的顺序表,第一个add方法会进行扩容,将顺序表的扩容为默认容量10

2.add方法的扩容是按照1.5倍扩容的

2.3 第三种构造方法

该构造方法的参数部分:

Collection<? extends E>为类型,c是变量

Collection是一个接口,ArrayList类实现了这个接口,所以这里的变量c可以是ArrayList类型,尖括号中?是通配符,继承了E类,意思就是尖括号中的泛型必须是E类型或E的子类型

三、ArrayList的一些方法

ArrayList类提供的方法大部分和上篇文章中模拟实现的方法一致,这里讲解一些没有模拟实现的方法:

1. boolean addAll(Collection<? extends E> c)

该方法为将一个顺序表的所有元素尾插到另一个顺序表:

public static void main(String[] args) {
    ArrayList<Integer> arrayList = new ArrayList<>();
    arrayList.add(1);
    arrayList.add(2);
    ArrayList<Integer> list = new ArrayList<>();
    list.add(3);
    list.addAll(arrayList);
    System.out.println(list); //结果为 [3, 1, 2]
}

2. E remove(int index)

删除index位置的元素:

    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.remove(0);
        System.out.println(arrayList); //结果为 [2]
    }

3. List<E> subList(int fromIndex, int toIndex)

左闭右开的区间截取顺序表中从fromIndextoIndex的元素,注意:这里的截取并不是指向一个新的对象,它依然指向原来的对象

    public static void main(String[] args) {
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
        arrayList.add(3);

        List<Integer> list = arrayList.subList(0, 2);//list依然指向原来的对象
        System.out.println(list); //结果为 [1, 2]

        list.set(0, 100);
        System.out.println(list); //[100, 2]
        System.out.println(arrayList); //[100, 1, 2]
    }

四、ArrayList的遍历

先创建一个顺序表:

ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);

4.1 for循环

for (int i = 0; i < arrayList.size(); i++) {
    System.out.print(arrayList.get(i) +" ");
}

4.2 for-each循环

for(Integer x : arrayList) { //:左边为顺序表中元素的类型+变量
    System.out.print(x +" ");
}

4.3 迭代器

1.Iterator接口中iterator()方法

Iterator<Integer> it = arrayList.iterator();
while(it.hasNext()) { 
    System.out.print(it.next() +" ");
    //判断是否有下一个元素,如果有则打印下一个元素,并将it指向下一个元素
}

2.ListIterator接口中listIterator()方法

ListIterator接口继承了Iterator接口,也可以作为迭代器遍历ArrayList

ListIterator<Integer> it1 = arrayList.listIterator();
while(it1.hasNext()) {
    System.out.print(it1.next() +" ");
}

3.利用迭代器从后往前打印

ListIterator<Integer> it2 = arrayList.listIterator(arrayList.size());
                                                    //这里要将顺序表的长度作为参数传过去
while(it2.hasPrevious()) {
    System.out.print(it2.previous() +" ");
    //判断是否有前一个元素,如果有则打印前一个元素,并将it指向前一个元素
}

🙉本篇文章到此结束,下篇文章会对链表相关知识进行讲解

文章来源:https://blog.csdn.net/m0_74270127/article/details/134842649
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。