zoukankan      html  css  js  c++  java
  • JavaSE学习笔记(十六)—— List集合

    一、List接口概述

    1.1 List概述

      有序(存储和取出的元素一致)的 collection(也称为序列)。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。与 set 不同,列表通常允许重复的元素。

    1.2 List案例

    【List集合存储字符串并遍历】

    public class ListDemo {
        public static void main(String[] args) {
            // 创建集合对象
            List list = new ArrayList();
    
            // 创建字符串并添加字符串
            list.add("hello");
            list.add("world");
            list.add("java");
    
            // 遍历集合
            Iterator it = list.iterator();
            while (it.hasNext()) {
                String s = (String) it.next();
                System.out.println(s);
            }
        }
    }

    【存储自定义对象并遍历】

    public class ListDemo {
        public static void main(String[] args) {
            // 创建集合对象
            List list = new ArrayList();
    
            // 创建学生对象
            Student s1 = new Student("白骨精", 30);
            Student s2 = new Student("蜘蛛精", 40);
            Student s3 = new Student("观音姐姐", 22);
    
            // 把学生对象添加到集合对象中
            list.add(s1);
            list.add(s2);
            list.add(s3);
    
            // 遍历
            Iterator it = list.iterator();
            while (it.hasNext()) {
                Student s = (Student) it.next();
                System.out.println(s.getName() + "---" + s.getAge());
            }
        }
    }

    二、List的特有功能

    2.1 基本功能

    【添加功能】

      void add(int index,Object element):在指定位置添加元素

    【获取功能】

      Object get(int index):获取指定位置的元素

    【列表迭代器】

      ListIterator listIterator():List集合特有的迭代器

    【删除功能】

      Object remove(int index):根据索引删除元素,返回被删除的元素

    【修改功能

      Object set(int index,Object element):根据索引修改元素,返回被修饰的元素

    public class ListDemo {
        public static void main(String[] args) {
            // 创建集合对象
            List list = new ArrayList();
    
            // 添加元素
            list.add("hello");
            list.add("world");
            list.add("java");
    
            // void add(int index,Object element):在指定位置添加元素
            // list.add(1, "android");//没有问题
            // IndexOutOfBoundsException
            // list.add(11, "javaee");//有问题
            // list.add(3, "javaee"); //没有问题
            // list.add(4, "javaee"); //有问题
    
            // Object get(int index):获取指定位置的元素
            // System.out.println("get:" + list.get(1));
            // IndexOutOfBoundsException
            // System.out.println("get:" + list.get(11));
    
            // Object remove(int index):根据索引删除元素,返回被删除的元素
            // System.out.println("remove:" + list.remove(1));
            // IndexOutOfBoundsException
            // System.out.println("remove:" + list.remove(11));
    
            // Object set(int index,Object element):根据索引修改元素,返回被修饰的元素
            System.out.println("set:" + list.set(1, "javaee"));
    
            System.out.println("list:" + list);
        }
    }

    2.2 遍历功能

    【使用普通for循环]

      List集合的特有遍历功能:size()和get()方法结合使用

    public class ListDemo {
        public static void main(String[] args) {
            // 创建集合对象
            List list = new ArrayList();
    
            // 添加元素
            list.add("hello");
            list.add("world");
            list.add("java");
    
            for (int x = 0; x < list.size(); x++) {
                String s = (String) list.get(x);
                System.out.println(s);
            }
        }
    }

      存储自定义对象并遍历,用普通for循环。(size()和get()结合)

    public class ListDemo3 {
        public static void main(String[] args) {
            // 创建集合对象
            List list = new ArrayList();
    
            // 创建学生对象
            Student s1 = new Student("林黛玉", 18);
            Student s2 = new Student("刘姥姥", 88);
            Student s3 = new Student("王熙凤", 38);
    
            // 把学生添加到集合中
            list.add(s1);
            list.add(s2);
            list.add(s3);
    
            // 遍历
            // 迭代器遍历
            Iterator it = list.iterator();
            while (it.hasNext()) {
                Student s = (Student) it.next();
                System.out.println(s.getName() + "---" + s.getAge());
            }
            System.out.println("--------");
    
            // 普通for循环
            for (int x = 0; x < list.size(); x++) {
                Student s = (Student) list.get(x);
                System.out.println(s.getName() + "---" + s.getAge());
            }
        }
    }

    【使用列表迭代器】

      ListIterator listIterator():List集合特有的迭代器。该迭代器继承了Iterator迭代器,所以,就可以直接使用hasNext()和next()方法。

      特有功能:

    • Object previous():获取上一个元素
    • boolean hasPrevious():判断是否有元素
    public class ListIteratorDemo {
        public static void main(String[] args) {
            // 创建List集合对象
            List list = new ArrayList();
            list.add("hello");
            list.add("world");
            list.add("java");
    
            // 迭代器
            Iterator it = list.iterator();
            while (it.hasNext()) {
                String s = (String) it.next();
                System.out.println(s);
            }
            System.out.println("----------");
    
            // ListIterator listIterator()
            ListIterator lit = list.listIterator();
            while (lit.hasPrevious()) {
                String s = (String) lit.previous();
                System.out.println(s);
            }
        }
    }

      注意:ListIterator可以实现逆向遍历,但是必须先正向遍历,才能逆向遍历,所以一般无意义,不使用。

    三、List的并发修改异常

      问题:我有一个集合,如下,请问,我想判断里面有没有"world"这个元素,如果有,我就添加一个"javaee"元素,请写代码实现。

    public class ListIteratorDemo {
        public static void main(String[] args) {
            // 创建List集合对象
            List list = new ArrayList();
            // 添加元素
            list.add("hello");
            list.add("world");
            list.add("java");
    
            // 迭代器遍历
            Iterator it = list.iterator();
            while (it.hasNext()) {
                String s = (String) it.next();
                if ("world".equals(s)) {
                    list.add("javaee");
                }
            }
    
        }
    }

      运行上述代码时,出现了这样的异常:

      

      ConcurrentModificationException:当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

    【产生的原因】

      迭代器是依赖于集合而存在的,在判断成功后,集合中新添加了元素,而迭代器却不知道,所以就报错了,这个错叫并发修改异常。
      其实这个问题描述的是:迭代器遍历元素的时候,通过集合是不能修改元素的

    【解决方法】

    • 方式一:迭代器迭代元素,迭代器修改元素(元素是跟在刚才迭代的元素后面的)
      public class ListIteratorDemo {
          public static void main(String[] args) {
              // 创建List集合对象
              List list = new ArrayList();
              // 添加元素
              list.add("hello");
              list.add("world");
              list.add("java");
      
              // 方式1:迭代器迭代元素,迭代器修改元素
              // 而Iterator迭代器却没有添加功能,所以我们使用其子接口ListIterator
              ListIterator lit = list.listIterator();
              while (lit.hasNext()) {
                  String s = (String) lit.next();
                  if ("world".equals(s)) {
                      lit.add("javaee");
                  }
              }
      
              System.out.println("list:" + list);//[hello, world, javaee, java]
          }
      }
    • 方式2:集合遍历元素,集合修改元素(元素在最后添加的)
      public class ListIteratorDemo {
          public static void main(String[] args) {
              // 创建List集合对象
              List list = new ArrayList();
              // 添加元素
              list.add("hello");
              list.add("world");
              list.add("java");
      
              // 方式2:集合遍历元素,集合修改元素(普通for)
              for (int x = 0; x < list.size(); x++) {
                  String s = (String) list.get(x);
                  if ("world".equals(s)) {
                      list.add("javaee");
                  }
              }
      
              System.out.println("list:" + list);//[hello, world, java, javaee]
          }
      }

    四、List接口的实现类

    4.1 ArrayList

    【ArrayList类概述】

      底层数据结构是数组,查询快,增删慢
      线程不安全,效率高

    【ArrayList案例】

      存储字符串并遍历

    public class ArrayListDemo {
        public static void main(String[] args) {
            // 创建集合对象
            ArrayList array = new ArrayList();
    
            // 创建元素对象,并添加元素
            array.add("hello");
            array.add("world");
            array.add("java");
    
            // 遍历
            Iterator it = array.iterator();
            while (it.hasNext()) {
                String s = (String) it.next();
                System.out.println(s);
            }
    
            System.out.println("-----------");
    
            for (int x = 0; x < array.size(); x++) {
                String s = (String) array.get(x);
                System.out.println(s);
            }
        }
    }

      ArrayList存储自定义对象并遍历

    public class ArrayListDemo2 {
        public static void main(String[] args) {
            // 创建集合对象
            ArrayList array = new ArrayList();
    
            // 创建学生对象
            Student s1 = new Student("武松", 30);
            Student s2 = new Student("鲁智深", 40);
            Student s3 = new Student("林冲", 36);
            Student s4 = new Student("杨志", 38);
    
            // 添加元素
            array.add(s1);
            array.add(s2);
            array.add(s3);
            array.add(s4);
    
            // 遍历
            Iterator it = array.iterator();
            while (it.hasNext()) {
                Student s = (Student) it.next();
                System.out.println(s.getName() + "---" + s.getAge());
            }
    
            System.out.println("----------------");
    
            for (int x = 0; x < array.size(); x++) {
                // ClassCastException 注意,千万要搞清楚类型
                // String s = (String) array.get(x);
                // System.out.println(s);
    
                Student s = (Student) array.get(x);
                System.out.println(s.getName() + "---" + s.getAge());
            }
        }
    }

      去除集合中字符串的重复值(字符串的内容相同)

    /*
     * 分析:
     *         A:创建集合对象
     *         B:添加多个字符串元素(包含内容相同的)
     *         C:创建新集合
     *         D:遍历旧集合,获取得到每一个元素
     *         E:拿这个元素到新集合去找,看有没有
     *             有:不搭理它
     *             没有:就添加到新集合
     *         F:遍历新集合
     */
    public class ArrayListDemo {
        public static void main(String[] args) {
            // 创建集合对象
            ArrayList array = new ArrayList();
    
            // 添加多个字符串元素(包含内容相同的)
            array.add("hello");
            array.add("world");
            array.add("java");
            array.add("world");
            array.add("java");
            array.add("world");
            array.add("world");
            array.add("world");
            array.add("world");
            array.add("java");
            array.add("world");
    
            // 创建新集合
            ArrayList newArray = new ArrayList();
    
            // 遍历旧集合,获取得到每一个元素
            Iterator it = array.iterator();
            while (it.hasNext()) {
                String s = (String) it.next();
    
                // 拿这个元素到新集合去找,看有没有
                if (!newArray.contains(s)) {
                    newArray.add(s);
                }
            }
    
            // 遍历新集合
            for (int x = 0; x < newArray.size(); x++) {
                String s = (String) newArray.get(x);
                System.out.println(s);
            }
        }
    }

      去除集合中字符串的重复值(字符串的内容相同),要求:不能创建新的集合,就在以前的集合上做。

    public class ArrayListDemo2 {
        public static void main(String[] args) {
            // 创建集合对象
            ArrayList array = new ArrayList();
    
            // 添加多个字符串元素(包含内容相同的)
            array.add("hello");
            array.add("world");
            array.add("java");
            array.add("world");
            array.add("java");
            array.add("world");
            array.add("world");
            array.add("world");
            array.add("world");
            array.add("java");
            array.add("world");
    
            // 由选择排序思想引入,我们就可以通过这种思想做这个题目
            // 拿0索引的依次和后面的比较,有就把后的干掉
            // 同理,拿1索引...
            for (int x = 0; x < array.size() - 1; x++) {
                for (int y = x + 1; y < array.size(); y++) {
                    if (array.get(x).equals(array.get(y))) {
                        array.remove(y);
                        y--;
                    }
                }
            }
    
            // 遍历集合
            Iterator it = array.iterator();
            while (it.hasNext()) {
                String s = (String) it.next();
                System.out.println(s);
            }
        }
    }

      去除集合中自定义对象的重复值(对象的成员变量值都相同)

    /*
     * 我们按照和字符串一样的操作,发现出问题了。
     * 为什么呢?
     *         我们必须思考哪里会出问题?
     *         通过简单的分析,我们知道问题出现在了判断上。
     *         而这个判断功能是集合自己提供的,所以我们如果想很清楚的知道它是如何判断的,就应该去看源码。
     * contains()方法的底层依赖的是equals()方法。
     * 而我们的学生类中没有equals()方法,这个时候,默认使用的是它父亲Object的equals()方法
     * Object()的equals()默认比较的是地址值,所以,它们进去了。因为new的东西,地址值都不同。
     * 按照我们自己的需求,比较成员变量的值,重写equals()即可。
     * 自动生成即可。
     */
    public class ArrayListDemo3 {
        public static void main(String[] args) {
            // 创建集合对象
            ArrayList array = new ArrayList();
    
            // 创建学生对象
            Student s1 = new Student("林青霞", 27);
            Student s2 = new Student("林志玲", 40);
            Student s3 = new Student("凤姐", 35);
            Student s4 = new Student("芙蓉姐姐", 18);
            Student s5 = new Student("翠花", 16);
            Student s6 = new Student("林青霞", 27);
            Student s7 = new Student("林青霞", 18);
    
            // 添加元素
            array.add(s1);
            array.add(s2);
            array.add(s3);
            array.add(s4);
            array.add(s5);
            array.add(s6);
            array.add(s7);
    
            // 创建新集合
            ArrayList newArray = new ArrayList();
    
            // 遍历旧集合,获取得到每一个元素
            Iterator it = array.iterator();
            while (it.hasNext()) {
                Student s = (Student) it.next();
    
                // 拿这个元素到新集合去找,看有没有
                if (!newArray.contains(s)) {
                    newArray.add(s);
                }
            }
    
            // 遍历新集合
            for (int x = 0; x < newArray.size(); x++) {
                Student s = (Student) newArray.get(x);
                System.out.println(s.getName() + "---" + s.getAge());
            }
        }
    }

    4.2 Vector

    【Vector类概述】

      底层数据结构是数组,查询快,增删慢
      线程安全,效率低

      注:Vector很少用了,现在ArrayList基本上取代了Vector。

    【Vector类特有功能】

      添加功能:public void addElement(Object obj) -- add()

      获取功能:

      public Object elementAt(int index)    -- get()
      public Enumeration elements()      -- Iterator iterator()
        boolean hasMoreElements()       hasNext()
        Object nextElement()             next()

    public class VectorDemo {
        public static void main(String[] args) {
            // 创建集合对象
            Vector v = new Vector();
    
            // 添加功能
            v.addElement("hello");
            v.addElement("world");
            v.addElement("java");
    
            // 遍历
            for (int x = 0; x < v.size(); x++) {
                String s = (String) v.elementAt(x);
                System.out.println(s);
            }
    
            System.out.println("------------------");
    
            Enumeration en = v.elements(); // 返回的是实现类的对象
            while (en.hasMoreElements()) {
                String s = (String) en.nextElement();
                System.out.println(s);
            }
        }
    }

    4.3 LinkedList

    【LinkedList类概述】

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

    【LinkedList类特有功能】

      A:添加功能
        public void addFirst(Object e)
        public void addLast(Object e)
      B:获取功能
        public Object getFirst()
        public Obejct getLast()
      C:删除功能
        public Object removeFirst()
        public Object removeLast()

    public class LinkedListDemo {
        public static void main(String[] args) {
            // 创建集合对象
            LinkedList link = new LinkedList();
    
            // 添加元素
            link.add("hello");
            link.add("world");
            link.add("java");
    
            // public void addFirst(Object e)
            // link.addFirst("javaee");
            // public void addLast(Object e)
            // link.addLast("android");
    
            // public Object getFirst()
            // System.out.println("getFirst:" + link.getFirst());
            // public Obejct getLast()
            // System.out.println("getLast:" + link.getLast());
    
            // public Object removeFirst()
            System.out.println("removeFirst:" + link.removeFirst());
            // public Object removeLast()
            System.out.println("removeLast:" + link.removeLast());
    
            // 输出对象名
            System.out.println("link:" + link);
        }
    }

    【练习】

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

      注意,题目的意思是:你自己的定义一个集合类,在这个集合类内部可以使用LinkedList模拟。

      MyStack.java

    /**
     * 自定义的栈集合
     */
    public class MyStack {
        private LinkedList linkedList;
    
        public MyStack() {
            linkedList = new LinkedList();
        }
    
        public void add(Object obj) {
            linkedList.addFirst(obj);
        }
    
        public Object get() {
            return linkedList.removeFirst();
        }
    
        public boolean isEmpty() {
            return linkedList.isEmpty();
        }
    }

      MyStackDemo.java

    /**
     * MyStack的测试
     */
    public class MyStackDemo {
        public static void main(String[] args) {
            // 创建集合对象
            MyStack myStack = new MyStack();
    
            // 添加元素
            myStack.add("hello");
            myStack.add("world");
            myStack.add("java");
    
            while (!myStack.isEmpty()) {
                System.out.println(myStack.get());
            }
        }
    }

    五、List集合的综合练习

    【题目一】

      集合的嵌套遍历

      需求:
      我们班有学生,每一个学生都是一个对象。所以我们可以使用一个集合表示我们班级的学生。ArrayList<Student>
      但是呢,我们旁边还有班级,每个班级也是一个ArrayList<Student>。
      而我现在有多个ArrayList<Student>。也要用集合存储,怎么办呢?
      就是这个样子的:ArrayList<ArrayList<Student>>

    public class ArrayListDemo {
        public static void main(String[] args) {
            // 创建大集合
            ArrayList<ArrayList<Student>> bigArrayList = new ArrayList<>();
    
            // 创建第一个班级的学生集合
            ArrayList<Student> firstArrayList = new ArrayList<>();
            // 创建学生
            Student s1 = new Student("唐僧", 30);
            Student s2 = new Student("孙悟空", 29);
            Student s3 = new Student("猪八戒", 28);
            Student s4 = new Student("沙僧", 27);
            Student s5 = new Student("白龙马", 26);
            // 学生进班
            firstArrayList.add(s1);
            firstArrayList.add(s2);
            firstArrayList.add(s3);
            firstArrayList.add(s4);
            firstArrayList.add(s5);
            // 把第一个班级存储到学生系统中
            bigArrayList.add(firstArrayList);
    
            // 创建第二个班级的学生集合
            ArrayList<Student> secondArrayList = new ArrayList<Student>();
            // 创建学生
            Student s11 = new Student("诸葛亮", 30);
            Student s22 = new Student("司马懿", 28);
            Student s33 = new Student("周瑜", 26);
            // 学生进班
            secondArrayList.add(s11);
            secondArrayList.add(s22);
            secondArrayList.add(s33);
            // 把第二个班级存储到学生系统中
            bigArrayList.add(secondArrayList);
    
            // 创建第三个班级的学生集合
            ArrayList<Student> thirdArrayList = new ArrayList<Student>();
            // 创建学生
            Student s111 = new Student("宋江", 40);
            Student s222 = new Student("吴用", 35);
            Student s333 = new Student("高俅", 30);
            Student s444 = new Student("李师师", 22);
            // 学生进班
            thirdArrayList.add(s111);
            thirdArrayList.add(s222);
            thirdArrayList.add(s333);
            thirdArrayList.add(s444);
            // 把第三个班级存储到学生系统中
            bigArrayList.add(thirdArrayList);
    
            // 遍历集合
            for (ArrayList<Student> students : bigArrayList) {
                for (Student student : students) {
                    System.out.println(student.getName() + "---" + student.getAge());
                }
            }
        }
    }

    【题目二】

      获取10个1-20之间的随机数,要求不能重复

    /**
     * 用数组实现,但是数组的长度是固定的,长度不好确定。所以我们使用集合实现。
     * 分析:
     *         A:创建产生随机数的对象
     *         B:创建一个存储随机数的集合。
     *         C:定义一个统计变量。从0开始。
     *         D:判断统计遍历是否小于10
     *             是:先产生一个随机数,判断该随机数在集合中是否存在。
     *                     如果不存在:就添加,统计变量++。
     *                     如果存在:就不搭理它。
     *             否:不搭理它
     *         E:遍历集合
     */
    public class RandomDemo {
        public static void main(String[] args) {
            // 创建产生随机数的对象
            Random random = new Random();
    
            // 创建一个存储随机数的集合
            ArrayList<Integer> arrayList = new ArrayList<>();
    
            // 定义一个统计变量。从0开始。
            int count = 0;
    
            // 判断统计遍历是否小于10
            while (count < 10) {
                //先产生一个随机数
                int number = random.nextInt(20) + 1;
    
                //判断该随机数在集合中是否存在。
                if (!arrayList.contains(number)) {
                    //如果不存在:就添加,统计变量++。
                    arrayList.add(number);
                    count++;
                }
            }
    
            // 遍历集合
            for (Integer i : arrayList) {
                System.out.println(i);
            }
        }
    }

    【题目三】

      键盘录入多个数据,以0结束,要求在控制台输出这多个数据中的最大值

    /**
     * 分析:
     *         A:创建键盘录入数据对象
     *         B:键盘录入多个数据,我们不知道多少个,所以用集合存储
     *         C:以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
     *         D:把集合转成数组
     *         E:对数组排序
     *         F:获取该数组中的最大索引的值
     */
    public class ArrayListDemo {
        public static void main(String[] args) {
            // 创建键盘录入数据对象
            Scanner sc = new Scanner(System.in);
    
            // 键盘录入多个数据,我们不知道多少个,所以用集合存储
            ArrayList<Integer> arrayList = new ArrayList<>();
    
            // 以0结束,这个简单,只要键盘录入的数据是0,我就不继续录入数据了
            while (true) {
                System.out.println("请输入数据:");
                int number = sc.nextInt();
                if (number != 0) {
                    arrayList.add(number);
                } else {
                    break;
                }
            }
    
            // 把集合转成数组
            // public <T> T[] toArray(T[] a)
            Integer[] i = new Integer[arrayList.size()];
            arrayList.toArray(i);
    
            // 对数组进行排序
            Arrays.sort(i);
    
            // 获取该数组中的最大索引的值
            System.out.println("数组是:" + Arrays.toString(i) + "最大值是:" + i[i.length - 1]);
        }
    }
  • 相关阅读:
    Hibernate延迟加载
    java.io.FileNotFoundException: antlr-2.7.7.jar (系统找不到指定的路径。)[待解决]
    Eclipse中复制项目重命名后重新发布,项目名在地址栏仍然是原来的项目名”的问题
    Tomcat服务器启动失败:Could not publish server configuration for Tomcat v8.0 Server at localhost. Multiple Contexts have a path of
    SSH整合:Unable to instantiate Action, employeeAction, defined for 'emp-list' in namespace '/'employeeAction
    ApplicationContext详解以及多个ApplicationContext.xml的相互引用
    Tomcat启动失败:Server Tomcat v8.0 Server at localhost was unable to start within 45 seconds
    三大框架你理解多少?
    通过命令行查询可用的包的版本号
    使用create-react-app命令创建一个项目, 运行npm run eject报错
  • 原文地址:https://www.cnblogs.com/yft-javaNotes/p/10856110.html
Copyright © 2011-2022 走看看