java学习-集合、list、泛型、迭代器、并发异常

一、集合体结构

  1.为什么使用集合?

   数组容器是定长容器, 当定义出一个数组,必须指定长度;

   集合容器,可以存放很多的数据, 但是集合是长度可变的容器(当集合容器中的数据存储空间不够, 系统会为集合进行自动扩容), 在实际开发中, 当并不知道数据有多少,集合就是最优秀的容器选择

  2.集合体系结构:

 

 

 

 

 

 

二、Collection集合

2.1 Collection的介绍和常用方法

  注意 : 所有集合中存储的元素全部都是引用数据类型:

  如果需要存储基本数据类型, 可以将基本类型进行自动装箱, 变成引用存储; 当使用集合中基本类型时, 再通过自动拆箱将数据获取到;

  1.Collection集合 : 所有单列集合顶层父接口, 来自于java.util包,所有单列集合都需要实现Collection中的所有方法功能, Collection集合中具有List和Set集合中所有共有方法

  2.Collection 是接口,不能实例化对象, 因此需要一个Collection的实现类, 找到ArrayList, 运用接口多态性

   Collection coll = new ArrayList();

  3.Collection中的常用方法:

    1) add(Object obj): 将参数obj添加到集合中, 末尾追加, 方法返回值类型boolean, 添加成功返回true,添加失败返回false

    2) remove(Object obj) : 将参数obj元素从集合中删除, 删除成功, 返回true, 如果删除失败, 返回false

    3) clear() : 表示清空集合, 将集合中的所有元素全部删除, 集合仍然存在

    4) isEmpty() : 验证集合中是否有元素, 如果没有元素,返回true; 如果有元素, 返回false

    5) size() : 表示获取到集合中元素的个数(获取集合的大小),返回值类型int类型              

    6) contains(Objectobj): 验证集合中是否包含参数obj,如果包含返回true. 如果不包含返回false

代码

public class Demo01_Collection常用方法 {

    public static void main(String[] args) {
        Collection coll = new ArrayList();
        // 1.add(Object obj): 将参数obj添加到集合中, 末尾追加, 
        // 方法返回值类型boolean, 添加成功返回true,添加失败返回false
        coll.add("a");
        coll.add("b");
        coll.add("c");
        coll.add("hello");
        
        System.out.println(coll);// [a, b, c, hello]
        System.out.println(coll.isEmpty());// false

        System.out.println(coll.contains("a"));// true
        System.out.println(coll.contains("c1"));// false
        
        // 2.remove(Object obj) : 将参数obj元素从集合中删除, 删除成功, 返回true,
        // 如果删除失败, 返回false
        System.out.println(coll.remove("c"));// true
        
        System.out.println(coll);// [a, b, hello]
        System.out.println(coll.size());// 3
        
        // 3. clear() : 表示清空集合, 将集合中的所有元素全部删除, 集合仍然存在
        coll.clear();
        System.out.println(coll);// []
        
  // 4. isEmpty() : 验证集合中是否有元素, 如果没有元素,返回true; 如果有元素, 返回false
       boolean boo =  coll.isEmpty();
       System.out.println(boo);// true
       
       // 5. size():表示获取到集合中元素的个数(获取集合的大小),返回值类型int类型
       System.out.println(coll.size());// 0      
    }

2.2 Collection集合的第一种遍历方式

  1. 集合遍历 : 表示将集合容器中的元素一个一个获取到

  2. 使用Collection中的方法 :

    toArray() : 将一个集合中的所有元素放置到一个数组中(集合转数组), 返回值类型Object[], 通过遍历数组相当于遍历集合

    注意 : 从Object类型数组中获取到的每一个元素,Object类型,想要转换成集合中数据类型本身, 需要做多态的向下转型

代码

public class Demo02_集合第一种遍历 {
    public static void main(String[] args) {
         Collection coll = new ArrayList();
         // 12--->自动装箱,Integer
         coll.add(12);
         coll.add(-78);
         coll.add(0);
         
         // 1. 将集合转换成数组
         Object[] objArr = coll.toArray();
         // 2. 遍历数组相当于遍历集合
         for(int index = 0; index < objArr.length; index++) {
             // 3. 从Object类型数组中获取到的每一个元素,Object类型
             // 想要转换成集合中数据类型本身, 需要做多态的向下转型
             Integer i = (Integer)objArr[index];
             System.out.println(i+1);
         }
    }
}

2.3 Collection中所有带All的方法

  1. addAll(Collection c) : 将参数集合c中的所有元素添加到方法调用集合中

  2. containsAll(Collection c) : 验证方法调用集合中的元素是否完全包含了参数c集合中的元素,如果完全包含, 返回true; 如果不是完全包含, 返回false

  3. removeAll(Collection c) :将参数c集合中的所有元素从方法调用集合中删除掉, boolean类型返回值结果(删除两个集合的交集)

  4. retainAll(Collection c) : 将方法调用集合与参数集合c中相同的元素保留下来, 同步到方法调用集合中(保留两个集合的交集)

代码

public class Demo03_Collection中All方法 {

    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        
        Collection c1 = new ArrayList();
        c1.add("Hello");
        c1.add("a");
        
        // 1. addAll(Collection c) : 将参数集合c中的所有元素添加到方法调用集合中
        c.addAll(c1);
        System.out.println(c);//[a, b, Hello, a]
           
        System.out.println("--------------");
        
        // 2. containsAll(): containsAll(Collection c) : 验证方法调用集合中的元素是否完全包含了参数c集合中的元素,如果完全包含, 返回true; 如果不是完全包含, 返回false
        boolean boo1 = c.containsAll(c1);
        System.out.println(boo1);// true
        
        Collection c2 = new ArrayList();
        c2.add("a1");
        c2.add("b");// [a1, b]
        
        System.out.println(c.containsAll(c2));// false
        System.out.println(c);// [a, b, Hello, a]
        System.out.println(c2);// [a1, b]
        
        // 3. removeAll(Collection c) :将参数c集合中的所有元素从方法调用集合中删除掉, 
        // boolean类型返回值结果(删除两个集合的交集)
        c.removeAll(c2);
        
        System.out.println(c+"----");// [a, Hello, a]
        
        
        // 4.retainAll(Collection c) : 将方法调用集合与参数集合c中重叠(相同)的元素保留下来,同步到方法调用集合中(获取两个集合的交集)
        
        Collection cc = new ArrayList();
        cc.add("ui");
        cc.add("world");
        
        Collection cd = new ArrayList();
        cd.add("ui1");
        cd.add("world1");
        
        Collection ce = new ArrayList();
        ce.add("ui");
        ce.add("world____");
        
        /*cc.retainAll(cd);
        System.out.println(cc);// []
*/        
        cc.retainAll(ce);
        System.out.println(cc);//[ui]
    }
}

2.4 Collection集合第二种迭代器遍历方式

  1.迭代 : 表示从一个到下一个的过程, 称为迭代

  2.迭代器 : 专门用于将集合中的元素一个一个获取到的对象

  3.迭代器对象的获取和使用:

    Collection父接口中, 有一个方法 iterator() , 返回值类型Iterator(接口,表示迭代器接口), 因此iterator() 方法实际返回的是Iterator接口的一个实现类对象

    Iterator : 迭代器中的方法

      1)hasNext() : 判断, 集合中是否还具有下一个元素, 如果有返回true; 如果没有返回false

      2)next() : 获取到集合中的下一个元素, 返回值类型Object

      3)remove() : 使用迭代器对象将目前正在迭代的元素从集合中删除

代码

public class Demo04_迭代器遍历集合 {

    public static void main(String[] args) {
        Collection c = new ArrayList();
        c.add("a");
        c.add("b");
        c.add("Hello");
        
        // 目前对于集合中有集合元素,未知,使用循环一次将元素从集合中获取到
        // 1. 获取一个集合的迭代器对象
        Iterator it = c.iterator();
        // 2. 使用迭代器中的nextInt()方法功能判断集合中是否具有下一个元素
        while(it.hasNext()) {
            // 3. 集合中有下一个元素,next获取到这个元素
            Object obj = it.next();
            String s = (String)obj;
            System.out.println(s);
        }
        
        // 4. 当集合已经遍历完毕, 但是还要通过next获取集合中的元素
        // 抛出异常 : NoSuchElementException
        System.out.println(it.next());
    }
}

三、 List集合

3.1 List集合的介绍和特有方法

  1.List集合是Collection接口的一个子接口,来自于java.util包

  2.List集合的特点:

    1) List集合中元素存储有序 : 存入集合的顺序与取出的顺序保持一致

    2) List集合中的元素都具有索引位置, 索引范围0---集合长度-1 (size()-1)

    3) List集合中存储的元素可以重复

  3.List中的特有方法: 都与索引操作有关

    1) add(int index, Object obj) : 将参数obj添加到集合指定索引index位置处

    2) remove(int index) : 将集合中指定index索引位置的元素删除, 返回值类型Object类型, 将删除的元素值进行返回

    3) set(int index, Object obj) : 将集合中指定index索引位置上的元素,使用obj进行替换, 返回值类型Object, 将被替换掉的原值进行返回

    4) get(int index) : 将集合中指定index索引位置上的元素获取到, 返回值类型Object

代码

public class Demo01_List特有方法 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("a");
        list.add("b");
        
        // 1. add(int index, Object obj) : 将参数obj添加到集合指定索引index位置处
        list.add(0, "第一");
        System.out.println(list);//[第一, a, b]
        
        // 2. remove(int index) : 将集合中指定index索引位置的元素删除, 返回值类型Object类型, 将删除的元素值进行返回
        Object obj = list.remove(1);
        System.out.println(obj);// a
        System.out.println(list);// [第一, b]
        
        // 3.set(int index, Object obj) : 将集合中指定index索引位置上的元素,使用obj进行替换, 返回值类型Object, 将被替换掉的原值进行返回
        Object obj1 = list.set(0, "替换");
        System.out.println(obj1);// 第一
        System.out.println(list);// [替换, b]
        
        // 4.get(int index) : 将集合中指定index索引位置上的元素获取到, 返回值类型Object
        Object obj2 = list.get(0);
        System.out.println(obj2);// 替换
        
        System.out.println(list.get(1));// b
        
        // 出现异常 : IndexOutOfBoundsException: Index: 2, Size: 2
        // System.out.println(list.get(2));
    }
}

3.2 List集合第三种遍历方式

  本种遍历方式是List集合特有的方法

  1.get(int index) : 将集合中指定index索引位置上的元素获取到

  2.如果能获取到一个集合的所有索引,那么可以通过get方法获取到集合中的每一个元素(与数组的遍历很相似)

  集合的索引范围 : 0---集合长度-1 (size()-1)

代码

public class Demo01_List第三种遍历 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("a");
        list.add("b");
        list.add("89");
        
        // 设计循环,获取集合中的每一个索引位置
        for(int index = 0; index < list.size(); index++) {
            // 使用get(index)方法即可
            System.out.println(list.get(index));
        }
    }
}

3.3并发修改异常

  1. ConcurrentModificationException 并发修改异常
  2. 异常发生原因 :

   当使用【迭代器对象】迭代集合同时, 使用【集合对象】向集合中添加或者删除元素, 导致迭代不能保证正确性, 于是报出并发修改异常

  3.异常解决方案:

    1) 迭代器对象迭代, 也使用迭代器对象修改

    2) 使用List集合特有遍历方式 : 索引

  4.实际解决方式:

    1) 迭代器对象迭代, 也使用迭代器对象修改

       在List接口中,有特殊方法:

      a :listIterator() : 返回值类型ListIterator(接口), 也是一个迭代器类型,但是在原有的迭代器功能基础上,支持一边迭代集合,一边修改集合中的元素,而避免发生并发修改异常.切记一定要使用迭代器对象修改集合元素

      b : ListIterator接口中的方法 :

        add(Object obj) : 使用迭代器对象向集合中添加元素obj

    2) 使用List集合特有遍历方式 : 索引

        因为for循环只是语法结构,不是任何类型 , 因此for循环本身不会发生异常; 并且每次for循环的条件都会实时获取到集合的长度, 也会适当的保证迭代的准确性

需求 : 定义出一个集合,集合中有三个元素 “hello” “world” “ok” , 遍历集合,当元素值匹配”hello”,向集合中添加元素”add”

代码

public class Demo03_并发修改异常 {
    /*需求 : 定义出一个集合,集合中有三个元素 “hello” “world” “ok” , 
    遍历集合,当元素值匹配”hello”时,向集合中添加元素”add”*/
    public static void main(String[] args) {
         List list = new ArrayList();
         list.add("hello");
         list.add("world");
         list.add("ok");
         
         /* 发生并发修改异常
          * Iterator it = list.iterator();
         while(it.hasNext()) {
             Object obj = it.next();
             String s = (String)obj;
             if("hello".equals(s)) {
                 list.add("add");
             }
         }
         
         System.out.println(list);*/
         
         // 并发修改异常第一种避免方案
         // 1. 获取到List集合特有的迭代器对象ListIterator
         /*ListIterator it = list.listIterator();
         while(it.hasNext()) {
             Object obj = it.next();
             String s = (String)obj;
             if("hello".equals(s)) {
                 // 2, 让迭代器对象给集合添加元素
                 // it.add("add");
                 it.remove();
             }
         }
         System.out.println(list);*/  
         
         // 并发修改异常第二种避免方案
         for(int index = 0; index < list.size(); index++) {
            String s = (String)list.get(index);
            if("hello".equals(s)) {
                  // list.add(0,"add");// [add,add,hello,world,ok] 造成死循环
                  list.add("add");
               }
         }
         System.out.println(list);// [hello, world, ok, add]
    }
}

3.4 List集合的实现类

  1. List接口, 需要实现类 : 根据底层实现不同,有不同的实现类
  2. List的实现类中,使用比较多的有2个

    1) ArrayList : 数组实现(ArrayList底层数组结构), 顺序存储

    2) LinkedList : 节点实现(可以利用内存中零散空间), 链式存储

  3.4.1ArrayList实现类

  1. ArrayList 实现类 : 数组实现(ArrayList底层数组结构), 顺序存储

    ArrayList查询快, 增加删除元素,相对比较慢

 

 

   

 

 

 

 

 

 

 

 

3.4.2 LinkedList实现类

  1. LinkedList : 节点实现(可以利用内存中零散空间), 链式存储

  LinkedList查询慢, 增加删除元素,相对比较快

    节点实现 : LinkedList中的元素节点存储, 每一个节点分为两个部分, 其中一个部分用于存储集合中的元素, 另外一个部分存储是下一个元素的地址值

 

 

 

 

 

 

 

 

 

  2.LinkedList类型中存储起始点内存地址(第一个元素); 还会存储最后一个节点内存地址(最后一个元素)

   因此LinkedList中对于第一个元素位置和最后一个元素的位置有特殊方法

    1) addFirst()

    2) addLast()

    3) removeFirst()

    4) removeLast()

    5) getFirst()

    6) getLast()

上述对于头尾操作的方法,性能比较高

代码

public class Demo04_LinkedList {
    public static void main(String[] args) {
         LinkedList list = new LinkedList();
         list.addFirst("a");
         list.addFirst("1");
         list.addLast("end");
         list.addLast("end1");
         
         System.out.println(list.getFirst());// 1
         System.out.println(list.getLast());// end1
         
         list.removeFirst();// 1
         list.removeLast();//  end1
         
         System.out.println(list);// [a, end]
    }
}

四、泛型

4.1 泛型的概述和使用(掌握)

  1. 泛型 : 表示广泛的类型(泛型是引用数据类型), 定义一个类型时, 对于这个类型中的一些方法参数或者返回值类型无法确定, 于是使用一个符号表示,这个符号称为泛型
  2. 泛型的使用:

    在类型声明后,使用<>,在菱形尖括号中,写入大写字母, 这些大写字母就表示泛型, 当创建出这个类型对象的时候, 需要确定泛型的具体类型

 确定泛型E具体类型时候: 

  a : 类上定义的泛型,可以在整个类中当做一个已知类型进行使用

  b : 举例 : ArrayList<E> , 这个E类型在ArrayList类中可以直接使用

    public boolean add(E e){} // E与ArrayList上面的广泛类型一致

    ArrayList<String> list = new ArrayList<>();

    list容器泛型确定为String类型, add方法参数类型就确定为String,调用时add(String s)

  1.泛型的好处:

    1) 提高代码的安全性, 将在运行环节会发生的问题提前到代码编译环节

    2) 提交代码的简洁性, 在集合中使用泛型,可以避免掉集合数据获取的向下转型操作

    3) 使用集合一定要使用泛型

  2.泛型写作的注意事项:

    1) 一致性 : 前后的泛型类型必须一致

    2) 泛型推断 : 从JDK1.7版本开始,后面的泛型可以不写, 只写<>, 默认后面的泛型类型与前面的类型保持一致

代码

public class Demo01_泛型的使用和好处 {
    public static void main(String[] args) {
        // 当创建出一个ArrayList集合容器时, 需要确定这个容器中存储的数据类型
        // 集合类型通过泛型的方式进行确定
        // list集合中只能存储Integer类型数据
       ArrayList<Integer> list = new  ArrayList<Integer>();
       list.add(12);
       list.add(13);
       list.add(14);
       list.add(15);
       
       for(int index = 0; index < list.size(); index++) {
           Integer i = list.get(index);
           System.out.println(i + 1);
       }
       
       ArrayList<String> list2 = new ArrayList<>();
       list2.add("abc");
       
       /*ArrayList list1 = new ArrayList();
       list1.add("a");
       list1.add(12);
       list1.add(3.14);
       
       for(int index = 0; index < list1.size(); index++) {
           Object obj = list1.get(index);
           String s = (String)obj;
           System.out.println(s); 
       }*/
    }
}

 

posted @ 2020-08-08 15:32  zcb_bai  阅读(204)  评论(0编辑  收藏  举报