Day16 --集合框架 ArrayList LinkedList 泛型 其他有关集合的

来源:互联网 发布:陕西广电网络是国企嘛 编辑:程序博客网 时间:2024/06/06 12:52
 a.
    代码实现
         1)集合框架(去除ArrayList中重复字符串元素方式)
             * 分析:
                * 1) 创建新集合对象用于存放不重复的元素。
                * 2) 使用老集合对象获取的 Iterator迭代器对象。
                * 3) 使用List中的contains方法判断是否有重复元素,如果没有就添加到新集合中。
                        * 创建方法:
                            *  返回值类型:ArrayList 参数类型:ArrayList list
使用List中的contains方法判断是否有重复的值出现,当!contains()方法时,重复的元素不出现,将不重复的元素存储到新集合中。
            

        2)去除ArrayList中重复自定义Bean对象元素
            注意:自定义Bean对象,并且重写toString 和 equals方法。
            分析:
                1)跟 去除ArrayList中重复字符串元素方式基本一样 还是将不重复的自定义对象元素存入到新集合中。
                2)关键点就是:自定义Bean对象中,是否重写了equals方法。如果没有重写equals方法还是使用的是Object中的equals方法,这样的判断是不会起到作用的。
                3)因为:List中的contains方法判断是否包含, 底层依赖的是equals方法。
                        List中的remove  方法p判断是否删除,底层同样依赖的是equals方法。
                关键: 关键是看自定义Bean的Animal对象中是否重写了equals方法
因为 contains方法判断是否包含元素对象,底层代码使用的是equals方法来进行判断的,只有自定义Bean的Aniaml对象中重写了Object的equals方法,并且有自己判断equals方法的标准,才能够在集合中存储不重复出现的值。        


b.
    LinkedList集合中特有功能
        概述
            * util包下。因为底层结构是 链表实现的,所以查询慢,修改也慢,但增删快。 它是线程不安全的,所以执行效率高。
        特有功能
            * public void addFirst(E e); 在开头位置添加元素
            * public void addLast(E e); 在末尾位置添加元素
            * public E getFrist(); 获取头部元素 如果链表为空,就抛出 NoSuchElementException
            * public E getLast();  获取结尾元素
            * public E removeFirst(); 删除开头位置元素,将删除的元素返回。
            * public E removeLast();  删除末尾位置元素,将删除的元素返回。
            * public E get(int index); 获取索引上的元素。
                * 由底层代码可知get的查找过程:
                    * 1)首先判断 当前索引上的元素是距离头部近 还是距离尾部近。
                    * 2)确定了1)的条件后,再一个一个元素的查找。
                    所以说,它的 查找还是比较慢的。


    栈和队列数据结构
        概述
            * 栈 (子弹夹)
                * 先进后出。
                    * 在LinkedList中表现的方法有:
                        * addLast[先进(压栈)。将一个个元素通过addLast的方式压进弹夹,而第一个先出来的是:最后压进的元素。] 所以说addFirst 是符合 栈 的数据结构。
                        
                        * removeLast[后出(弹栈)。删除最后一个元素,往往都是压入弹夹的第一个元素子弹]
            * 队列(水管道)
                * 先进先出。
                    * 在LinkedList中表现的方法有:
                        * addLast[先进(先进)。将一个个元素,通过addLast的方式流进水管道,而第一个先进入的元素,往往第一个先出来,以此类推。]
                        
                        * removeFirst[先出(先出)。删除第一个元素,往往都是流进水管道的第一个元素水滴]


    用LinkedList模拟【栈】数据结构的集合并测试
        代码实现:参考
            D:\CSDN_Android_\Code\Day16_集合框架 ArrayList LinkedList 泛型 其他有关集合的\src\com\day16\a\list\Demo04_用LinkedList模拟_栈_数据结构的集合并测试.java
            D:\CSDN_Android_\Code\Day16_集合框架 ArrayList LinkedList 泛型 其他有关集合的\src\com\day16\a\list\Demo05_根据Demo04来创建一个Stack类用于模拟栈结构的LinkedList方法.java

d.
    泛型
        概述
            * 它是一种安全机制,可以接收 任意引用数据类型, 将运行期的错误转换成编译期。 
            * 用于限定类存储的类型,或是该类型的子类对象。
        使用它的好处
            * 提高安全性。(将运行期的错误转换成编译期)
                * 注意
                    * 如果限定了集合的类型,在添加元素对象的时,就只能添加该泛型指定的类型,如果添加其他类型的元素对象,就会出现错误,所以说 将运行时期的错误 转换成 编译时期,这样提前避免错误,提高代码了安全性。
                    * 同样避免了强转的麻烦。
                    
            * 省去了 强转 的麻烦。
        使用方式
            * <T> 中放入的是引用数据类型。
        注意事项
            * <T> 中必须是引用数据类型
            * 前后的泛型必须一致,或者后面的泛型可以省略不写(这是jdk1.7的新特性:菱形泛型)
            *     * 菱形泛型:ArrayList<Animal> al = new ArrayList<>();
            * 泛型一般不定义为 Object, 因为这样没有意义。
        

注意:泛型只有在编译期有效,在生成.class文件后运行期时泛型会被自动擦除掉
所以可以通过反射拿到该字节码文件,从而改变该集合泛型原本限定的数据类型 这个过程就叫做泛型反射(泛型擦除)

    ArrayList存储字符串和自定义对象并遍历泛型版
        案例
            * ArrayList存储字符串并遍历泛型版
            * ArrayList存储自定义对象并遍历泛型版


    泛型的由来
        概述
            * 泛型的由来,是由Ojbect类型的转换问题而引入的。
            * 早期的Object类型可以接受任意的对象类型,但在实际使用中,会有类型转换的问题的出现,这样就存在了一定的安全隐患,所以Java才为我们提供泛型来解决这一安全问题。
    

    泛型类的概述及使用
        概述
            * 泛型类
                * 将泛型定义在类上
            * 格式 
                * public class 类名<泛型>
        注意事项
            * 类的泛型同样必须是引用数据类型。
             
        
        注意:
            方法泛型,最好和类的泛型一致。如果不一致,就在方法上声明该不同的泛型。
            * 如:
                * 类设置为泛型:
                    * public class Tools<E> {}
                * 不同的方法泛型:
                    * public<T> void work(T t){
                            System.out.println(t);
                      } 
              泛型方法    
                * 将泛型定义在方法声明上
              格式
                * public <泛型类型> 返回值类型 方法名(泛型类型 变量名){}    
                * 同类一样的方法泛型:
                    * public void work(E e){
                            System.out.println(e);
                      } 
                * 不同的方法泛型:
                    * public<T> void work(T t){
                            System.out.println(t);
                      } 
                
             
                静态方法的泛型,不要和类的泛型一致,因为静态是随着类的加载而加载,在类创建后还没有调用过方法,所以静态方法要有自己的泛型。
                * 格式
                    * public static<泛型> 返回值类型 方法名(泛型 变量名){}
                * 静态方法
                    * public static<Q> void print(Q q){
                         System.out.println(q);
                      }
            泛型接口
                概述
                    * 将泛型定义在接口上
                格式
                    * public interface 接口名<泛型类型>
                    * public interface Inter<T>{}
                    * public class demo implments Inter<T>{}    
                注意
                    * 一个类实现一个泛型接口:
                        * a:类实现接口的同时,给定具体的类型。--推荐使用
                            * class Demo implements Inter<String>{ //推荐使用
                                    public void show(String str){
                                        System.out.println("Tools.Demo.show()");
                                    }
                                }    

                        * b: 类进行沿用接口的泛型,同时还可以定义类自己的泛型。--没有必要在具体类实现接口的时候给自己类再加泛型。
                            * class Demo2<T> implements Inter<T>{
                                   public void show(T t){
                                         System.out.println("Tools.Demo.show()");
                                   }
                              }
                            
            泛型的通配符
                概述    
                  * 当在开发中,如果后续代码功能不能够确定类型,就用通配符?先来标识
                  * 泛型通配符<?>
                      * 任意类型,如果没有明确,那么就用Object以及任意的Java类。
                  * ? extends E        --这种写法叫:固定上边界。
                      * 向下限定,此时的?能够是E以及E的子类
                  * ? super E --固定下边界    
                      * 向上限定,此时的?能够是E以及E的父类    


e.
    增强for
        概述
            * 是一种简化数组和Collection集合的遍历方式
        格式
            for(元素数据类型 变量名:数组或Collection集合){
                使用变量即可,该变量就是元素。
            }
        注意:增强for循环,依赖的是迭代器(普通迭代器)
    


    ArrayList存储字符串和自定义对象并遍历增强for版    
        * 代码实现
        

需求:测试_三种迭代方式能否删除集合元素对象
         1)普通for    --size() 和 get(int index);  能删除,但要索引--;
                 * 为什么要 索引-- 的原因?
                     * i-- 的原因是:如果当集合中有两个或两个以上重复出现的元素在上下顺序排列。当满足删除的条件时,该索引
                     上的元素就会被删除, 而后面元素自动向上补齐。for循环中i++,指针就会向后移动一位,如果自动补齐的第一个元素也满足
                     删除条件,但指针往后移动了一次,就漏过了当前也满足删除条件的元素,就会出现漏删的可能。所以必须要将i--,让指针
                     往上走一次,让指针重新出现在 已经被删除的元素的上一个元素继续判断,这样就不会出现漏删的可能了。    
         
         2)Iterator   --hasNext() 和next()  -- 能删除。但必须使用普通迭代器自己的remove()方法,而不能使用集合自带的remove(Object o)方法,思路和ListIterator中自带的add()方法相同。
                 
                 
         3)增强for  --不能删除。
                 * 虽然增强for 底层同样使用的普通迭代器来删除元素。但是此时的增强for删除元素还是用集合自带的remove(int index);方法删除,所以不能删除集合元素,如果强要删除就会出现:并发修改异常。
     
    迭代器的注意事项:
            当集合添加元素时:
                * 必须使用List中特有的ListIterator迭代器来遍历元素,且用ListIterator自带的add()方法去添加元素,否则会出现 并发修改异常。
            当集合删除元素时:
                * 必须使用普通迭代器 Iterator 中自己的remove()方法去删除元素,否则会出现 并发修改异常,思路和ListIterator中自带的add()方法相同。


f.
    静态导入
        由来
            * 一边使用的导入(导包) 导入的是包中的类。而静态导入,是导入类中的静态方法。
        概述
            * 静态导入是导入类中的静态方法
        格式
            * import static 包名...。类名。方法名;
            * 可以直接导入到方法的级别
        静态导入的弊端
            * 当使用静态导入,即:import static java.util.Arrays.sort;时,对int数组的排序有原来的:Arrays.sort(arr) 变成了直接:sort(arr)。如果该类还行定义一个 静态的同名sort方法就不能创建成功。
            * 所以静态导入,一般不使用,只有看得懂即可。
            
        注意事项
            * 方法必须是静态的,如果出现多个同名的静态方法。容易不知道该具体使用谁。
                * 这个时候要使用,必须加前缀。前缀是:java.包.类.静态方法。
                * 如:java.util.Arrays.toString(arr);
                * 由此可见,意义不大,所以一般不用,但是要能看懂。
                *【静态导入只能导入静态方法,不能导入非静态方法】
                
Arrays是操作数组的类。 Math是操作数字的类。这两个类中所有方法都是静态的。



g.
    可变参数 -- ChangeableArgs        able表示可变的,Args表示参数的缩写。
        概述
            * 当定义方法的时候不知道该具体定义多少个参数,就用可变参数来代替。
            * 这里的可变参数可以是 0到多个。
        格式
            * 访问修饰符 返回值类型 方法名(数据类型 ... 变量名){}
            * 访问修饰符 返回值类型 方法名(数据类型... 变量名){} --推荐使用
        注意事项
            * 可变参数其实是一个数组,调用该含有可变参数的方法时,参数直接可以是一个数组的具体表现形式。
                * 如: 当定义可变参数的方法时: public static void print(int... arr){}; 具体调用时是:print(1,2,3,4,5);  这里的12345就是具体的可变参数,即一个数组。     
            * 如果一个方法中有可变参数的存在,并且有多个参数。那么可变参数肯定是最后一个。
                * 如: public static void print(int a, int b,int... arr){}  //这里的可变参数必须是最后一个参数,这是规矩。


h.
    Arrays工具类的asList()方法的使用
        概述
            * Arrays中的asList()方法的作用是:【数组转集合】
                    * 好处:是能够对数组转集合后的元素进行查询和修改,不能添加和删除。     
                    * 异常:UnsupportedOperationException 不支持请求的操作时,就会抛出该异常。
                                  当数组转集合,添加或删除元素时,就会出现:UnsupportedOperationException    
            * Collection中的toArray()方法的作用是:【集合转数组】
        注意
            * 数组转集合asList 不能添加或删除元素,但可以查询或修改元素。
            * 如果是基本数据类型的数组转集合,会将整个数组当作一个对象来转成集合的,因为集合中只能存储引用数据类型,所以将其当成对象后 就是一个引用数据类型了。
            * 如果调用的数组长度等于集合的size,那么数组的长度就是size。
                * 当集合转数组时,数组的长度如果小于等于集合的size时,转换后的数组长度就等于集合的size     
                * 当数组长度大于size,分配的数组长度就和你指定的长度一样。
                
        代码参考:D:\CSDN_Android_\Code\Day16_集合框架 ArrayList LinkedList 泛型 其他有关集合的\src\com\day16\d\jdk5\Demo06_Arrays工具类中的asList方法的使用.java
    


i.
    集合嵌套之ArrayList嵌套ArrayList
    代码:
        ArrayList<ArrayList<Animal>> list = new ArrayList<>();
//        狗狗品种一
        ArrayList<Animal> first = new ArrayList<>();
        first.add(new Animal("金毛",2));
        first.add(new Animal("拉布拉多",3));
        first.add(new Animal("秋田犬",4));
        
//        狗狗品种二
        ArrayList<Animal> two = new ArrayList<>();
        two.add(new Animal("德国牧羊犬",8));
        two.add(new Animal("中华田园犬",5));
        two.add(new Animal("藏獒",6));
        
//        将两个品种级别的添加到一个集合中去
        list.add(first);
        list.add(two);
        
//        集合嵌套集合的遍历方式
//        使用增强for遍历
        for (ArrayList<Animal> a : list) { //拿到所有狗狗品种
            for (Animal al : a) {    //分别获取到每个狗狗品种中的狗狗、
                System.out.println(al);
            }
        }
    

-- 几种删除集合元素的方式
    1)    正着遍历 size()和get(),使用集合自带的remove(int index)方法,但必须要i--,i--的原因是为了防止漏删下一个也是相同元素。
    
    2)    普通迭代器:Iterator 使用Iterator自带的remove()方法删除。
    3)     List自带的迭代器:ListIterator 使用ListIterator自带的remove()方法删除。    
    4) 倒着遍历 size()和get()
        关键:
        for(int i = list.size()-1;i>=0;i--){
            if("c".equals(list.get(i))){
                list.remove(i); //下面没有下面再必要i--,因为for循环中i--就表示当前指针在已经被删除元素的下一位元素了。
            }
        }
原创粉丝点击