《Java基础:ArrayList类的解释使用(最全篇)》

(一)ArrayList类介绍

ArrayList是一个基于数组上的链表,但是不同的是ArrayList不是同步的。所以在性能上要比Vector好一些,但是当运行到多线程环境中时,可需要自己在管理线程的同步问题。

1.1:语法

ArrayList() 
构造一个初始容量为 10 的空列表(每次递增容量的一半)
ArrayList(Collection<? extends E> c) 
构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的 
ArrayList(int initialCapacity) 
构造一个具有指定初始容量的空列表

 

1.2:特殊方法

void ensureCapacity(int minCapacity) 
如有必要,增加此 ArrayList 实例的容量,以确保它至少能够容纳最小容量参数所指定的元素数。 
返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1。 
protected  void removeRange(int fromIndex, int toIndex) 
移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素。

 

1.3:遍历

package com.itlwc;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Test {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        list.add("lwc");
        list.add("nxj");
        // 遍历方法一
        Iterator<String> ite1 = list.iterator();
        while (ite1.hasNext()) {
            String str = ite1.next();
            System.out.println(str);
        }
        System.out.println("---------------------");
        // 遍历方法二(方法一的变形)
        for (Iterator<String> ite2 = list.iterator(); ite2.hasNext();) {
            String str = ite2.next();
            System.out.println(str);
        }
        System.out.println("---------------------");
        // 遍历方法三
        for(String s : list){
            System.out.println(s);
        }
    }
}
/*
打印结果:
	lwc
	nxj
	---------------------
	lwc
	nxj
	---------------------
	lwc
	nxj
*/

1.4:总结

(1)ArrayList依赖于数组实现的,初始长度为10的Object[],并且可随需要而增加的动态数组当元素超过10,那么ArrayList底层会新生成一个数组,长度为原来的1.5倍+1,然后将原数组内容复制到新数组中,并且后续增加的内容会放到新数组中,当新数组无法容纳增加的元素,重复该过程。

(2)ArrayList对随机访问性能很好,但进行大量插入,删除操作,性能很差,因为操作之后后续元素需要移动。


 

1.5:实例

public class ArrayListReview {
    public static void main(String[] args) {
        ArrayList<Info> infosList=new ArrayList<>();
        infosList.add(new Info(0, "aaa"));
        infosList.add(new Info(1, "bbb"));
        infosList.add(new Info(2, "ccc"));
        infosList.add(new Info(3, "ddd"));
        infosList.add(1, new Info(4, "eee")); // 按索引插入到指定位置

        // foreach遍历输出
        for (Info info : infosList) {
            System.out.println(info);
        }
        System.out.println("------------------------");

        // 截取字串
        List<Info> subList = infosList.subList(1, 3);
        subList.add(new Info(30, "fly"));
        printList(subList);

        ArrayList<Info> newInfosList=new ArrayList<>();
        newInfosList.add(new Info(11, "qqq"));
        newInfosList.add(new Info(12, "www"));

        ArrayList<String> ss=new ArrayList<>();
        //      infosList.addAll(newInfosList);  // 添加一个指定集合到原集合最后,注意两个集合的泛型参数一致
        infosList.addAll(2,newInfosList); // 将指定集合插入到指定位置
        //printList(infosList);

        Info info = infosList.get(2);  // 取出指定位置的元素
        System.out.println(info);

        infosList.set(0, new Info(10, "rrr"));   // 替换指定索引位置的元素
        //printList(infosList);

        int index = infosList.indexOf(info);  //根据元素获取元素第一次出现的索引,不存在则返回-1
        int lastIndex = infosList.lastIndexOf(info); // 取出元素的最后一个匹配项的索引
        int indexOf = infosList.indexOf(new Info(4,"eee")); // 重写了Info类的hashCode与equals方法,用于判断两个对象是否相同
        System.out.println("index="+indexOf);
        //printList(infosList);

        // 通过反射拿到的removeRange方法
        removeRange(infosList, 1, 3);
        //printList(infosList);

        // listIterator从前往后迭代
        ListIterator<Info> listIterator = infosList.listIterator();
        while(listIterator.hasNext()){
            // 最后抛出错误,java.util.NoSuchElementException,不要每次取都掉用next方法,它每调用一次,迭代器指针向前移动一位
            //          System.out.println("id="+listIterator.next().getId()
            //                  +"adress="+listIterator.next().getAdress()); 

            Info next = listIterator.next();  // 正确做法,调用一次要取出元素,然后操作属性
            System.out.println("id="+next.getId()
                               +" adress="+next.getAdress()); 
        }

        // 往前迭代,必须在往后迭代之后用
        while(listIterator.hasPrevious()){  // 当有上一个元素时
            Info previous = listIterator.previous();  // 获取上一个元素
            System.out.println("id="+previous.getId()+" adresss="+previous.getAdress());
        }

        // 通过数组来转化成一个List,虽然可以把数组转成集合,但是集合的长度不能改变。
        String[] a=new String[]{"hello","world","just","do","it"};
        List<String> asList = Arrays.asList(a);
        //asList.add("gogogo");  //不可修改asList,会抛出UnsupportedOperationException

        // 泛型使用 
        //      ArrayList<Object> l=new ArrayList<String>();// 不行
        //      ArrayList<ArrayList> lll=new ArrayList<List>(); // 不行
        //      ArrayList<List> lll=new ArrayList<ArrayList>(); // 不行
        //      ArrayList l=new ArrayList<String>(); // 可行
        //      ArrayList<String> l=new ArrayList<>(); // 可行
        //      ArrayList ll=new ArrayList();  // 可行
    }

    // 打印输出
    public static <E> void printList(List<E> list) {
        for (E e : list) {
            System.out.println(e);
        }
        System.out.println("------------------------");
    }
}

(二)ArrayList遍历的3种方法

2.1:Iterator方法遍历

for(Iterator it2 = list.iterator();it2.hasNext();){
    System.out.println(it2.next());
}

 

2.2:for 第一种循环方式遍历

for(int i = 0;i < list.size(); i ++){
    System.out.println(list.get(i));
}

 

2.3:for 第二种循环方式遍历

for(String tmp:list){
    System.out.println(tmp);
}

 

2.4:实例

public class ListTest {
    public static void main(String[] args)
    {
        List<String> list = new ArrayList<String>();
        long start = 0L;
        long end = 0L;
        for(int j = 0; j < 1000000; j++)
        {
            list.add("aaaaaa" + j);
        }

        start = System.currentTimeMillis();
        for(String tmp:list)
        {
        }
        end = System.currentTimeMillis();
        System.out.print("第一种方法运行时间:" + (end - start) + "(毫秒)\n");


        start = System.currentTimeMillis();
        for(int i = 0; i < list.size(); i++)
        {
            list.get(i);
        }
        end = System.currentTimeMillis();
        System.out.print("第二种方法运行时间:" + (end - start) + "(毫秒)\n");


        Iterator<String> iter = list.iterator();

        start = System.currentTimeMillis();
        while(iter.hasNext())
        {
            iter.next();
        }
        end = System.currentTimeMillis();
        System.out.print("第三种方法运行时间:" + (end - start) + "(毫秒)\n");            
    }
}

执行的结果:

第一种方法运行时间:14(毫秒)
第二种方法运行时间:4(毫秒)
第三种方法运行时间:5(毫秒)

2.5:总结

1、方式1,3看着比较简洁,但是性能较差,这种方式在循环的过程中,会进行数据锁定,性能较差。
2、第二种方式,循环过程中数据不锁定,效率高,但是多线程的时候需要考虑并发操作的问题.
3、第一种方式比第三钟方式还要多一些处理,所以时间更久。
因此推荐用第二种

(三)ArrayList删除特定不同元素(2种)

3.1:使用下标的方式删除

在代码中,删除元素后,需要把下标减一。这是因为在每次删除元素后,ArrayList会将后面部分的元素依次往上挪一个位置(就是copy),所以,下一个需要访问的下标还是当前下标,所以必须得减一才能把所有元素都遍历完。

ArrayList al = new ArrayList();
al.add("a");
al.add("b");
al.add("b"); 
al.add("c"); 
for (int i = 0; i < al.size(); i++) {
    if (al.get(i) == "b") {
        al.remove(i);
        i--;//一定要移动下标,不然会报错
    }
}

3.2:使用Iterator元素遍历的方式删除

两种方案实现原理都差多的,性能也差别不大,第二种只是jdk封装了下。

Iterator<String> sListIterator = list.iterator();  
while(sListIterator.hasNext()){  
    String e = sListIterator.next();  
    if(e.equals("3")){  
        sListIterator.remove();  
    }  
}
 

(四)ArrayList删除重复元素(2种)

4.1:使用HashSet删除ArrayList中重复的元素

public static void main(String[] args)  
{  
    //Constructing An ArrayList  
    ArrayList<String> listWithDuplicateElements = new ArrayList<String>();  
    listWithDuplicateElements.add("JAVA");  
    listWithDuplicateElements.add("J2EE");  
    listWithDuplicateElements.add("JSP");  
    listWithDuplicateElements.add("SERVLETS");  
    listWithDuplicateElements.add("JAVA");  
    listWithDuplicateElements.add("STRUTS");  
    listWithDuplicateElements.add("JSP");  
    //Printing listWithDuplicateElements  
    System.out.print("ArrayList With Duplicate Elements :");  
    System.out.println(listWithDuplicateElements);  
    //Constructing HashSet using listWithDuplicateElements  
    HashSet<String> set = new HashSet<String>(listWithDuplicateElements);  
    //Constructing listWithoutDuplicateElements using set  
    ArrayList<String> listWithoutDuplicateElements = new ArrayList<String>(set);  
    //Printing listWithoutDuplicateElements  
    System.out.print("ArrayList After Removing Duplicate Elements :");  
    System.out.println(listWithoutDuplicateElements);  
}

输出:

注意输出结果。你会发现,在删除重复元素之后,元素重新洗牌。不再按照插入顺序排列。如果你想在删除重复的元素之后依然保持元素的插入顺序,那么不 建议使用此方法。还有另一种方法,可以保证在删除重复的元素之后也不改变元素的插入顺序。那就是使用LinkedHashSet。

ArrayList With Duplicate Elements :[JAVA, J2EE, JSP, SERVLETS, JAVA, STRUTS, JSP]
ArrayList After Removing Duplicate Elements :[JAVA, SERVLETS, JSP, J2EE, STRUTS]

4.2:使用LinkedHashSet删除ArrayList中重复的元素

public static void main(String[] args)  
{  
    //Constructing An ArrayList  
    ArrayList<String> listWithDuplicateElements = new ArrayList<String>();  
    listWithDuplicateElements.add("JAVA");  
    listWithDuplicateElements.add("J2EE");  
    listWithDuplicateElements.add("JSP");  
    listWithDuplicateElements.add("SERVLETS");  
    listWithDuplicateElements.add("JAVA");  
    listWithDuplicateElements.add("STRUTS");  
    listWithDuplicateElements.add("JSP");  
    //Printing listWithDuplicateElements  
    System.out.print("ArrayList With Duplicate Elements :");  
    System.out.println(listWithDuplicateElements);  
    //Constructing LinkedHashSet using listWithDuplicateElements  
    LinkedHashSet<String> set = new LinkedHashSet<String>(listWithDuplicateElements);  
    //Constructing listWithoutDuplicateElements using set  
    ArrayList<String> listWithoutDuplicateElements = new ArrayList<String>(set);  
    //Printing listWithoutDuplicateElements  
    System.out.print("ArrayList After Removing Duplicate Elements :");  
    System.out.println(listWithoutDuplicateElements);  
}

输出:
注意输出。你可以发现在删除ArrayList中的重复元素后,依然保持了元素的插入顺序。

ArrayList With Duplicate Elements :[JAVA, J2EE, JSP, SERVLETS, JAVA, STRUTS, JSP]
ArrayList After Removing Duplicate Elements :[JAVA, J2EE, JSP, SERVLETS, STRUTS]

(五)ArrayList合并并删除重复数据(3种)

5.1:通过List自带方法list.retainAll()

List temp=new ArrayList(l1);//用来保存两者共同有的数据
temp.retainAll(l2);//temp中只保留两者共同的数据
l1.removeAll(temp);//l1中去掉两者共同有的数据
List l3=new ArrayList();
l3.addAll(l1);
l3.addAll(l2);
System.out.println(l3);

5.2:构造Set集合。Set集合本身是不允许重复记录的

Set s=new TreeSet(l1);
for(Integer i:l2){
    //当添加不成功的时候 说明s中已经存在该对象
    s.add(i);
}
System.out.println(s);

5.3:遍历列表,对比数据

public static ArrayList addArrayList(ArrayList list1, ArrayList list2) {
    ArrayList list3 = new ArrayList();
    if (list1 == null || list1.size() == 0) {
        list3 = list2;
    } else if (list2 == null || list2.size() == 0) {
        list3 = list1;
    } else {
        for (int i = 0; i < list1.size(); i++) { // 遍历list1
            boolean isExist = false;
            for (int j = 0; j < list2.size(); j++) {
                if (list1.get(i).equals(list2.get(j))) {
                    isExist = true; // 找到相同项,跳出本层循环
                    break;
                }
            }
            if (!isExist) { // 不相同,加入list3中
                list3.add(list1.get(i));
            }
        }

        for (int k = 0; k < list2.size(); k++) {
            list3.add(list2.get(k));
        }
    }
    return list3;
}

(六)ArrayList排序的3种方法

6.1:使用Collections.sort()方法进行排序

(1)ArrayList 存储着以字符串形式存在的国名(country name),为了对这个 ArrayList 进行排序,你需要调用 Collections.sort()方法。

(2)这种方法将按照自然顺序(按字母升序)对元素(国名)进行排序。代码如下:

public class SortArrayListAscendingDescending {
    private ArrayList arrayList;
    public SortArrayListAscendingDescending(ArrayList arrayList) {
        this.arrayList = arrayList;
    }
    public ArrayList getArrayList() {
        return this.arrayList;
    }
    public ArrayList sortAscending() {
        Collections.sort(this.arrayList);
        return this.arrayList;
    }
    public ArrayList sortDescending() {
        Collections.sort(this.arrayList, Collections.reverseOrder());
        return this.arrayList;
    }
}

(3)在SortArrayListAscendingDescending类中,我们在构造器中初始化了一个 ArrayList 对象。在 sortAscending()方法中,我们调用了 Collections.sort()方法,并传递这个初始化的 ArrayList对象为参数,返回排序后的 ArrayList。

(4)在 sortDescending()方法中,我们调用重载的 Collections.sort()方法让其按照降序对元素排序,这个版本的 Collections.sort()接收ArrayList对象作为第一个参数,一个由 Collections.reverseOrder()方法返回的 Comparator 对象作为第二个参数。

public class SortArrayListAscendingDescendingTest {
    public void testSortAscendingDescending() throws Exception {
        ArrayList countryList = new ArrayList();
        countryList.add("France");
        countryList.add("USA");
        countryList.add("India");
        countryList.add("Spain");
        countryList.add("England");

        SortArrayListAscendingDescending sortArrayList = new SortArrayListAscendingDescending(countryList);
        ArrayList unsortedArrayList = sortArrayList.getArrayList();
        System.out.println("Unsorted ArrayList: " + unsortedArrayList);

        ArrayList sortedArrayListAscending = sortArrayList.sortAscending();
        System.out.println("Sorted ArrayList in Ascending Order : " +
                           sortedArrayListAscending);

        ArrayList sortedArrayListDescending = sortArrayList.sortDescending();
        System.out.println("Sorted ArrayList in Descending Order: " +
                           sortedArrayListDescending);
    }
}

(5)在SortArrayListAscendingDescendingTest测试代码中,我们创建一个 ArrayList 对象,并添加了 5 个字符串对象代表 5 个国家的名字。然后我们调用 getArrayList()、sortAscending()和 sortDescending()方法,并打印这些方法返回的 ArrayList 对象。

显示结果:

------------------------------------------------------- 
T E S T S 
-------------------------------------------------------   
Running guru.springframework.blog.sortarraylist.ascendingdescending.SortArrayListAscendingDescendingTest   
Unsorted ArrayList: [France, USA, India, Spain, England] 
Sorted ArrayList in Ascending Order : [England, France, India, Spain, USA] 

Sorted ArrayList in Descending Order: [USA, Spain, India, France, England]   
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.001 sec - in guru.springframework.blog.sortarraylis

6.2:使用Comparable排序

(1)让我们来举一个例子,JobCandidate 类的对象保存在 ArrayList 中并准备对其进行排序。

(2)JobCandidate 类有三个成员变量:字符串类型的姓名和性别、整型的年龄。我们想要对保存在 ArrayList 中的 JobCandidate 对象按照年龄进行排序。因此我们要让 JobCandidate 类实现 Comparable 接口并重写 compareTo()方法。

public class JobCandidate implements Comparable {
    private String name;
    private String gender;
    private int age;

    public JobCandidate(String name, String gender, int age) {
        this.name = name;
        this.gender = gender;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public String getGender() {
        return gender;
    }

    public int getAge() {
        return age;
    }

    @Override
    public int compareTo(JobCandidate candidate) {
        return ((this.getAge() < candidate.getAge()) ? (-1)
                : ((this.getAge() == candidate.getAge())
                   ? 0 : 1));
    }

    @Override
    public String toString() {
        return " Name: " + this.name + ", Gender: " + this.gender + ", age:" +
        this.age;
    }
}

(3)JobCandidate 类被重写的 compareTo()方法中,我们实现了基于年龄的比较逻辑。

public class JobCandidateSorter {
    ArrayList jobCandidate = new ArrayList<>();
    public JobCandidateSorter(ArrayList jobCandidate) {
        this.jobCandidate = jobCandidate;
    }
    public ArrayList getSortedJobCandidateByAge() {
        Collections.sort(jobCandidate);
        return jobCandidate;
    }
}

(4)在 JobCandidateSorter 类中,我们初始化了一个 ArrayList 对象,委托方将通过构造函数实例化 JobCandidateSorter 。然后我们编写了 getSortedJobCandidateByAge()方法,在这个方法中,我们调用 Collections.sort()并传递已经初始化了的 ArrayList 为参数,最后返回排序后的 ArrayList。

public class JobCandidateSorterTest {
    public void testGetSortedJobCandidateByAge() throws Exception {
        JobCandidate jobCandidate1 = new JobCandidate("Mark Smith", "Male", 26);
        JobCandidate jobCandidate2 = new JobCandidate("Sandy Hunt", "Female", 23);
        JobCandidate jobCandidate3 = new JobCandidate("Betty Clark", "Female",
                                                      20);
        JobCandidate jobCandidate4 = new JobCandidate("Andrew Styne", "Male", 24);
        ArrayList jobCandidateList = new ArrayList();
        jobCandidateList.add(jobCandidate1);
        jobCandidateList.add(jobCandidate2);
        jobCandidateList.add(jobCandidate3);
        jobCandidateList.add(jobCandidate4);

        JobCandidateSorter jobCandidateSorter = new JobCandidateSorter(jobCandidateList);
        ArrayList sortedJobCandidate = jobCandidateSorter.getSortedJobCandidateByAge();
        System.out.println("-----Sorted JobCandidate by age: Ascending-----");

        for (JobCandidate jobCandidate : sortedJobCandidate) {
            System.out.println(jobCandidate);
        }
    }
}

JobCandidateSorterTest类中,我们创建了四个 JobCandidate 对象并把它们添加到 ArrayList,然后传递这个 ArrayList 到构造函数来实例化 JobCandidateSorter 类。最后,我们调用 JobCandidateSorter 类的 getSortedJobCandidateByAge()方法,并打印这个方法返回的排序后的 ArrayList。

测试的输出结果如下:

------------------------------------------------------- 
T E S T S 
------------------------------------------------------- 
Running guru.springframework.blog.sortarraylist.comparable.JobCandidateSorterTest 
-----Sorted JobCandidate by age: Ascending----- 
Name: Betty Clark, Gender: Female, age:20
Name: Sandy Hunt, Gender: Female, age:23
Name: Andrew Styne, Gender: Male, age:24
Name: Mark Smith, Gender: Male, age:26
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.003 sec 
- in guru.springframework.blog.sortarraylist.comparable.JobCandidateSorterTest

6.3:使用 Comparator 排序

比如我有一个Person类,它的实例对象存储在ArrayList数组中,现在要把ArrayList数组中的Person对象按照年龄排序.代码如下:

Person类

public class Person {
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;

    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

}

Mycomparator类

public class Mycomparator implements Comparator {

    public int compare(Object o1, Object o2) {
        Person p1 = (Person) o1;
        Person p2 = (Person) o2;
        if (p1.age < p2.age) return 1;
        else return 0;
    }

}

ListSort类

当然,如果你的List包装的是基本类型或者String,则只要 Collections.sort(list);即可

public class ListSort {
    public static void main(String[] args) {
        ArrayList list = new ArrayList();
        list.add(new Person("lcl", 28));
        list.add(new Person("fx", 23));
        list.add(new Person("wqx", 29));
        Comparator comp = new Mycomparator();
        Collections.sort(list, comp);
        for (int i = 0; i < list.size(); i) {
            Person p = (Person) list.get(i);
            System.out.println(p.getName());
        }
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大大大钢琴

喜欢!就请他吃3块钱好吃的吧!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值