Java中的Collection集合(List类集合)

1、集合和数组的区别

  • 数组作为一种容器,有一些不方便之处,在进行增、删、改操作的时候很不方便,并且数组只能存储同一数据类型,可以是基本数据类型,也可以是引用数据类型。Java提出集合的概念,集合也是一种容器,它只能存储引用,集合不是某一个类,而是一个集合框架,有很多种集合构成。 以下是Collection集合的继承体系:
    在这里插入图片描述

2、Collection集合

  • Collection 是层次结构中的根接口,Collection 表示一组对象,这些对象也称为 collection 的元素。该集合在java.util包下。

Collection的功能概述(通过API查看即可得到)——
添加功能:
1、boolean add(Object obj):添加一个元素
2、boolean addAll(Collection c):添加一个集合的元素 (给一个集合添加进另一个集合中的所有元素)
删除功能:
3、void clear():移除所有元素
4、boolean remove(Object o):移除一个元素
5、boolean removeAll(Collection c):移除一个集合的元素(移除一个以上返回的就是true) 删除的元素是两个集合的交集元素 ,如果没有交集元素 则删除失败 返回false
判断功能:
6、boolean contains(Object o):判断集合中是否包含指定的元素
7、boolean containsAll(Collection c):判断集合中是否包含指定的集合元素(这个集合包含另一个集合中所有的元素才算包含 才返回true)【比如:1,2,3 containsAll 12=true 1,2,3 containsAll 2,3,4=false】
8、boolean isEmpty():判断集合是否为空
获取功能:
9、Iterator<E> iterator()(重点),迭代器可以认为是指针
长度功能:
10、int size():元素的个数
交集功能:
【例如:A集合对B集合取交集,获取到的交集元素在A集合中。返回的布尔值表示的是A集合是否发生变化】
11、boolean retainAll(Collection c):获取两个集合的交集元素(交集:两个集合都有的元素)
把集合转换为数组:
12、Object[] toArray()

package org.westos.demo3;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
public class Collection集合
{
    public static void main(String[] args)
    {
        Collection c=new ArrayList();//需要一个接口类型的变量,使用实现接口的子类,多态的形式
        boolean b = c.add(12);
        boolean b1 = c.add(true);
        boolean b2 = c.add('c');
        boolean b3 = c.add(new Student());
        boolean b4 = c.add(new int[2]);//所有的返回值都代表是否添加元素成功
        System.out.println(c);//打印集合,发现输出的是集合里面的元素,所以,该集合一定是重写了toString()

        boolean b5 = c.remove(12);//根据元素移除集合里面的元素,返回结果为是否移除成功

        Collection c1=new ArrayList();
        c1.add(12);
        c1.add(true);
        System.out.println(c.removeAll(c1));//true
        System.out.println(c);
        //移除一个集合的元素(移除一个以上返回的就是true),删除的元素是两个集合的交集元素
        //如果没有交集元素 则删除失败 返回false

        c.add(1);
        c.add(2);
        c.add(3);
        c.add(4);
        c.add(5);
        c1.add(1);
        c1.add(2);
        c1.add(3);
        c1.add(4);
        c1.add(5);
        System.out.println(c.contains(1));//判断是否包含该元素,true
        System.out.println(c.containsAll(c1));//判断集合c包含c1,false

        c.clear();//移除所有元素

        System.out.println(c.isEmpty());//判断集合是否为空,true

        System.out.println(c1.size());//获取集合的元素个数,7

        c.add(1);
        System.out.println(c.retainAll(c1));//获取两个集合的交集元素(交集:两个集合都有的元素),false

        Object[] obj = c1.toArray();//集合转为数组
        System.out.println(Arrays.toString(obj));//[12, true, 1, 2, 3, 4, 5]
    }
}
  • 关于迭代器:
    迭代器是一种设计模式,它可以遍历并选择序列中的对象,而开发人员不需要了解该序列的底层结构(迭代器把访问逻辑从不同类型的集合类里面抽取出来,从而避免向外部暴露集合的内部结构)。迭代器通常被认为是“轻量级”对象,因为创建它的代价小。
  • 为什么要使用迭代器?
    若不使用迭代器,访问代码和集合本身是紧密耦合的,因此无法将访问逻辑从集合类和客户端代码中分离出来。而由于不同的集合会对应不同的遍历方法,所以客户端代码无法复用。而对Iterator来说,它总是用同一种逻辑来遍历集合,使得客户端自身不需要维护集合的内部结构,所有的内部状态都由Iterator来维护。
  • 实现原理:
    下面基于ArrayList的Iterator的实现分析Iterator的原理(基于JDK1.8):在ArrayList类中有一个方法 iterator() ,此方法将返回一个iterator的实现,这里可以看出实现类交叫Itr,通过它的源码可知,这是ArrayList的一个内部类。为什么要将迭代器设置为内部类,因为内部类(无论是成员内部类还是局部内部类)可以访问外部类里面的所有成员,包括私有的成员。
    在这里插入图片描述
package org.westos.demo3;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class MyTest1
{
    public static void main(String[] args)
    {
        Collection c=new ArrayList();
        c.add(1);
        c.add(2);
        c.add(3);
        c.add(4);
        c.add(5);
        Iterator iterator = c.iterator();//使用该方法获取迭代器,Iterator接口对Collection集合进行遍历的迭代器
        while(iterator.hasNext())
        {//迭代器可以认为是指针
            System.out.println(iterator.next());//判断是否存在下一个元素,如果存在就获取并输出
        }
        System.out.println("迭代器输出为:"+iterator);//java.util.ArrayList$Itr@1540e19d
        //打印这个迭代器会发现里面有一个美元符号,说明这个迭代器类是内部类
    }
}

3、List子接口

  • 元素序列有序(存取顺序一致),并且每一个元素都有索引,集合中允许元素重复。

List集合的特有功能概述:
void add(int index,E element): 在指定索引处添加元素
E remove(int index):移除指定索引处的元素 返回的是移除的元素
E get(int index):获取指定索引处的元素
E set(int index,E element):更改指定索引处的元素 返回的而是被替换的元素

package org.westos.demo3;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MyTest2
{
    public static void main(String[] args)
    {
        List list=new ArrayList();//多态
        list.add("三国演义");
        list.add("水浒传");
        list.add("西游记");
        list.add(0,"红楼梦");//List集合中特有的添加元素的方法,根据索引添加元素
        list.remove("红楼梦");
        list.remove(0);//List集合中特有的删除元素的方法,根据索引删除元素

        list.add(0);
        list.add(1);
        list.add(2);
        list.add(3);
        list.remove(1);//这里的1只能代表索引,不是元素1,如果区分不出来元素还是索引,将元素包装
        list.remove(Integer.valueOf(1));

        System.out.println("集合中第一个元素为:"+list.get(0));//list中的特有的方法,根据索引获取元素,注意索引越界
        list.set(0,"儒林外史");//根据索引替换元素

        System.out.println(list);//[儒林外史, 0, 2, 3]
    }
}
  • 遍历List集合的几种方式:
package org.westos.demo3;

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

public class MyTest3
{
    public static void main(String[] args)
    {
        List list = new ArrayList();
        list.add("碎琉璃");
        list.add("穆斯林的葬礼");
        list.add("鲁迅");
        list.add("冰心");
        list.add("巴金");

        //方式1;
        Iterator i=list.iterator();
        while(i.hasNext())
        {
            System.out.println(i.next());
        }

        //方式2:
        for (int j = 0; j < list.size(); j++)
        {
            System.out.println(list.get(j));
        }

        //方式3:List集合自己有一个迭代器
        ListIterator listIterator = list.listIterator();
        //这个迭代器的父接口是Iterator,它里面的方法比父接口中的方法丰富,可以反向迭代
        while(listIterator.hasPrevious())
        {
            System.out.println(listIterator.previous());
        }
        //注意:反向迭代的时候,必须先进行正向迭代,因为迭代就相当于一个指针,而且注意正向反向迭代的必须是一个迭代器
    }
}

4、并发修改异常

  • 首先看一段代码:
package org.westos.demo3;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class MyTest4
{
    public static void main(String[] args)
    {
        List list=new ArrayList();
        list.add("C/C++");
        list.add("Java");
        list.add("PHP");
        list.add("JavaScript");
        list.add("Python");
        list.add("Matlab");
        ListIterator iterator=list.listIterator();
        while(iterator.hasNext())
        {
            String str= (String) iterator.next();
            if(str.equals("PHP"))
                list.add("C#");
          //ConcurrentModificationException,此处程序会报并发修改异常
        }
    }
}
  • 为什么会出现这样的错误?
    当我们使用迭代器遍历集合的时候,我们的迭代器已经事先知道集合元素的个数,突然在迭代途中增加或者删除元素,就会打乱原来集合的顺序,迭代器也就无所适从,就会抛出并发修改异常。解决方式有两种:1、使用迭代器自己的增加删除集合中元素的方法 2、使用for循环遍历,就可以使用集合自己的增加和删除方式,修改后的代码如下:
package org.westos.demo3;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

public class MyTest4
{
    public static void main(String[] args)
    {
        List list=new ArrayList();
        list.add("C/C++");
        list.add("Java");
        list.add("PHP");
        list.add("JavaScript");
        list.add("Python");
        list.add("Matlab");

        ListIterator iterator=list.listIterator();
        while(iterator.hasNext())
        {
            String str= (String) iterator.next();
            if(str.equals("PHP"))
                iterator.add("C#");//解决方式 1
        }
        System.out.println(list);//[C/C++, Java, PHP, C#, JavaScript, Python, Matlab]

        for (int i = 0; i < list.size(); i++)
        {
            String str= (String) list.get(i);
            if(str.equals("PHP"))
                list.add("C#");//解决方式 2
        }
        System.out.println(list);//[C/C++, Java, PHP, C#, JavaScript, Python, Matlab, C#]
    }
}

5、不同集合的特点

  • List:数组元素有序,允许元素重复,选择哪种集合,根据自己的需求而定在这里插入图片描述

6、ArrayList集合

  • 实现了Collection接口和List接口,在 java.util 包下,常用的方法如下:

1、boolean add(E e) :将指定的元素添加到此列表的尾部
2、void add(int index, E element):将指定的元素插入此列表中的指定位置
3、void clear() :移除此列表中的所有元素
4、Object clone() :返回此 ArrayList 实例的浅表副本
5、boolean contains(Object o):如果此列表中包含指定的元素,则返回 true
6、 E get(int index):返回此列表中指定位置上的元素
6、 int indexOf(Object o) :返回此列表中首次出现的指定元素的索引,或如果此列表不包含元素,则返回 -1
7、boolean isEmpty() :如果此列表中没有元素,则返回 true
8、int lastIndexOf(Object o):返回此列表中最后一次出现的指定元素的索引,或如果此列表不包含索引,则返回 -1
9、E remove(int index):移除此列表中指定位置上的元素
10、boolean remove(Object o) :移除此列表中首次出现的指定元素(如果存在)
11、protected void removeRange(int fromIndex, int toIndex):移除列表中索引在 fromIndex(包括)和 toIndex(不包括)之间的所有元素
12、E set(int index, E element):用指定的元素替代此列表中指定位置上的元素
13、int size() :返回此列表中的元素数
14、Object[] toArray():按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组

package org.westos.demo3;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.function.Consumer;

public class MyTest5
{
    public static void main(String[] args)
    {
        ArrayList a = new ArrayList();
        a.add(100);
        a.add(200);
        a.add(300);
        a.add(100);
        a.add(267);
        a.add(383);
        a.add(157);
        int i = a.indexOf(100);
        System.out.println("元素100在集合a中的索引为:"+i);//0
        System.out.println("元素100在集合a中最后一次出现的索引为:"+a.lastIndexOf(100));//3

        a.sort(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Integer a= (Integer) o1;
                Integer b= (Integer) o2;
                return a-b;
            }
        });//排序集合中的元素
        System.out.println("集合中的元素为:"+a);//[100, 100, 157, 200, 267, 300, 383]

        List list = a.subList(0, 2);
        System.out.println("根据索引截取出来的集合为:"+list);//[100, 100]

        Object o = a.clone();
        System.out.println("浅克隆出来的元素为:"+o);//[100, 100, 157, 200, 267, 300, 383]

        //JDK1.8给ArrayList集合提供了一个内部迭代
        a.forEach(new Consumer() {
            @Override
            public void accept(Object o) {
                System.out.println(o);
            }
        });
    }
}

【案例】去除集合中的重复元素:要求是不能创建新的容器,就在原来的集合当中,去掉重复元素

package org.westos.demo4;

import java.util.ArrayList;
import java.util.ListIterator;

public class MyTest1
{
    public static void main(String[] args)
    {
        ArrayList list=new ArrayList();
        list.add(100);
        list.add(100);
        list.add(100);
        list.add(100);
        list.add(100);
        list.add(200);
        list.add(300);
        list.add(400);
        list.add(100);
        list.add(200);
        list.add(400);
        list.add(500);
        list.add(100);
        list.add(200);
        list.add(300);
        list.add(400);
        //方式1-----原理:类似于选择排序
        deleteEle(list);

        //方式2------递归
        ArrayList list1=removeEle(list);
        System.out.println(list1);//[500, 100, 200, 300, 400]
    }

    private static ArrayList removeEle(ArrayList list)
    {
        for (int i = 0; i < list.size(); i++)
        {
            if(list.indexOf(list.get(i))!=list.lastIndexOf(list.get(i)))
            {
                list.remove(list.get(i));
                removeEle(list);
            }
        }
        return list;
    }

    private static void deleteEle(ArrayList list)
    {
        for (int i = 0; i < list.size()-1; i++)
        {
            for (int j = i+1; j < list.size(); j++)
            {
                if (list.get(i).equals(list.get(j)))
                {
                    list.remove(j);
                    j--;
                }
            }
        }
        System.out.println(list);//[100, 200, 300, 400, 500]
    }
}

7、Vector集合

  • Vector集合底层数据结构仍然是数组,因此具有查询快,增删慢的特点,线程安全,效率低,因此一般不常用。以下是它的一些常用的方法:

1、boolean add(E e):将指定元素添加到此向量的末尾
2、void add(int index, E element) :在此向量的指定位置插入指定的元素
3、void addElement(E obj):将指定的组件添加到此向量的末尾,将其大小增加 1
4、E elementAt(int index) :返回指定索引处的组件
5、E firstElement():返回此向量的第一个组件(位于索引 0) 处的项)
6、void removeElementAt(int index):删除指定索引处的组件
7、List<E> subList(int fromIndex, int toIndex):返回此 List 的部分视图,元素范围为从 fromIndex(包括)到 toIndex(不包括)
8、Object[] toArray():返回一个数组,包含此向量中以恰当顺序存放的所有元素

package org.westos.demo4;

import java.util.Enumeration;
import java.util.Vector;

public class Vector{
   public static void main(String[] args)
   {
       Vector vector = new Vector();
       vector.add("aaa");
       vector.addElement("bbb");
       vector.add("ccc");
       vector.add("ddd");
       vector.add("eee");
       vector.add("fff");

       System.out.println(vector.get(0));//aaa
       System.out.println(vector.elementAt(0));//一个作用--aaa

       System.out.println(vector.firstElement());//aaa
       System.out.println(vector.lastElement());//fff

       //vector.removeAllElements();//清空所有元素

       //自带的迭代器
       Enumeration elements = vector.elements();
       while(elements.hasMoreElements())
       {
           System.out.println(elements.nextElement());
       }
   }
}

8、linkedList集合

  • 底层是链表,查询慢,增删快,线程不安全,效率高

LinkedList类特有功能:
public void addFirst(E e):添加元素至集合最前面
addLast(E e):添加元素至集合最后面
public E getFirst():获取第一个元素
getLast();获取第二个元素
public E removeFirst():移除第一个元素
public E removeLast():移除第二个元素

【案例】 请用LinkedList模拟栈数据结构的集合,并测试

//测试类:
package org.westos.demo4;

public class MyTest2
{
    public static void main(String[] args)
    {
        //用LinkedList集合模拟栈数据结构,先进后出
        MyList myList=new MyList();
        myList.addEle("abc1");
        myList.addEle("abc2");
        myList.addEle("abc3");
        myList.addEle("abc4");
        myList.addEle("abc5");

        Object obj=myList.getEle();
        System.out.println(obj);

        Object obj1 = myList.getEle();
        System.out.println(obj1);

        System.out.println(myList.toString());//[abc3, abc2, abc1, abc5, abc4]
    }
}
//工具类:
package org.westos.demo4;

import java.util.LinkedList;

public class MyList
{
    LinkedList list=null;

    public MyList(){
        list=new LinkedList();
    }

    public void addEle(Object obj)
    {
        list.addFirst(obj);
        //list.push(obj);---往链头添加元素
    }

    public Object getEle()
    {
        Object o = list.pop();
        //list.addFirst(o);---自己的错误做法
        list.addLast(o);//正确的做法
        return o;
    }

    @Override
    public String toString() {
        return list.toString();
    }
}

【案例】ArrayList去除集合中字符串的重复值(字符串的内容相同)

//已有类去重:
package org.westos.demo4;
import java.util.ArrayList;
public class MyTest3
{
    public static void main(String[] args)
    {
        ArrayList list = new ArrayList();
        list.add("aaa");
        list.add("bbb");
        list.add("aaa");
        list.add("ccc");
        list.add("bbb");
        list.add("ddd");
        list.add("bbb");
        list.add("aaa");
        list.add("ccc");
        list.add("bbb");
        list.add("ddd");
        //去除集合中的重复元素
        //采用创建新集合的方式来做
        ArrayList newList = new ArrayList();
        for (int i = 0; i < list.size(); i++)
        {
            Object o = list.get(i);//去重装到新集合
            if(!newList.contains(o))
            {
                newList.add(o);
            }

        }
        System.out.println(newList);//[aaa, bbb, ccc, ddd]

    }
}
//自定义类去重————
//测试类:
package org.westos.demo4;
import java.util.ArrayList;
public class MyTest4
{
    public static void main(String[] args)
    {
        ArrayList list=new ArrayList();
        list.add(new Student("张三",19));
        list.add(new Student("李四",20));
        list.add(new Student("王五",23));
        list.add(new Student("赵六",18));
        list.add(new Student("张三",19));
        list.add(new Student("王五",23));

        ArrayList newList = new ArrayList();

        for (int i = 0; i < list.size(); i++)
        {
            Student stu = (Student) list.get(i);
            if(!newList.contains(stu)){
                //要想判断是否存在这个Student对象,如果直接这样写的话一定是错的
                //每次存储的时候都是new新对象,contains()方法在判断的时候调用equals(),比较的是地址值
                //但是我们重写Student类的equlas()和hashCode(),contains()方法调用重写过后的equals()方法,比较的是字段值
                newList.add(stu);
            }
        }
        System.out.println(newList);
    }
}
//自定义的Student类:
package org.westos.demo4;
import java.util.Objects;
public class Student
{
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //重写这两个方法比较的是姓名和年龄这两个字段
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
发布了13 篇原创文章 · 获赞 8 · 访问量 392

猜你喜欢

转载自blog.csdn.net/weixin_45082647/article/details/104047492