zoukankan      html  css  js  c++  java
  • 疯狂Java学习笔记(017)·集合类

    一、ArrayList 对自定义类对象去重

      1.思路:创建新集合,从原集合里拿出元素放入新集合,放入的同时做判断使用的是contains方法。

      通过查看contains方法的源码,实际上调用的是要添加元素的equals方法。

      如果要添加元素对已经存在的元素调用equals方法,返回true表面已经存在;返回false表面不存在。

      默认equals是继承自Object类的,只是简单的比较地址,自定义类要重写equals方法,告知虚拟机到底什么情况下才是“相等”的。

    二、并发修改异常(ConcurrentModificationException)

      在使用迭代器遍历ArrayList的时候,使用集合本身的方法修改集合,将导致并发修改异常:

      两种方法:

      1.使用迭代器遍历,使用迭代器删除元素。

      2.使用集合本身遍历,使用集合本身方法删除元素。

      如果添加元素:

      查看Iterator接口的方法,没有添加元素的方法,但是它的子接口ListIterator有。

      1.ListIterator迭代,迭代器添加元素。

      2.集合本身迭代,使用集合本身方法添加元素。

    三、Vector类

      Vector类是1.0就已经有了,在1.2被整合到集合框架中,其中的大部分方法都和ArrayList相同,但是它是线程安全的,所以效率低。

      特有方法:

    •   addElement( );
    •   removeElement( );
    •   elements( );

    四、LinkedList类

    •   LinkedList类底层使用的是链表结构保存数据。
    •   绝大多数方法和ArrayList相同,只不过多了一些对首尾元素操作的方法。
    •   包括:
    •     addFirst( )
    •     addLast( )
    •     remove( )

      LinkedList底层使用得是链表,但是自己维护了一个索引,所以,提供了get(int index)的方法来通过索引获取元素,但此方法的效率很低,一般不使用。

     五、关于List接口的实现类的选择

    •   需要线程安全的话是选择Vector,但是也可以通过其他方式让其他两种类也达到线程安全,所以,一般也不会使用Vector。
    •   不需要线程安全的话,考虑是增删多还是查询多:增删多,使用LinkedList;查询多,使用ArrayList.
    •   ArrayList比较通用。

    六、泛型

      需要了解的方面:

    • JDK1.5的新特性
      1. 在JDK1.5之前,把对象放到集合中,集合不会记住元素的类型,取出时,全都变成Object类型。
      2. 集合接口,集合类中出现的<>就是泛型,即参数化类型<>中的字母代表的是类型。
      3. 提高了程序的安全性,不符合类型的元素不能添加。
      4. 将运行期遇到的问题转移到了编译期。
      5. 记住了元素的类型,取出元素时省区了类型强转的麻烦。
    • 泛型出现的原因

        业务场景:如一个学生类,包含一个score成员变量,有可能时以下类型:int,double,String,因此为了方便,统一使用Object类型的变量接收。

        问题:取出之后的类型容易出现类型转换异常

    • 泛型类 泛型方法

        泛型类:在类上添加一个类型的定义,在使用类时指定一个类型,就可以对传入的数据进行类型检查,在取出时,不必进行类型转换了,这样的类就是泛型类。

            泛型接口,泛型抽象!

            把泛型定义到接口,类名后。

            在类中就可以使用泛型当成一个类型。

            成员变量的类型,方法返回值类型,方阿飞的形参类型,方法中的局部变量类型。

            new后不能用泛型。

        泛型类的缺点:每次针对不同的类型的参数,都必须创建不同类型的对象。这是的方法依赖于创建对象时的类型,他们之间的耦合度太高,为了降低这种耦合度,可以把泛型定义在方法上,这就是泛型方法。

        泛型方法:

         把泛型放到方法上定义!

        方法的返回值,形参类型,方法内部的局部变量类型。

        泛型没有多态性:

        想要实现泛型的类似多态性的用法,使用泛型通配符

        

        ?:任何类型都可以用

        ?extends A:A类和A类的子类可以使用

        ? super A:A类和A类的父类可以使用!

        Set接口:元素不重复

        不同的子类对重复的理解不同

          HashSet:使用哈希算法对元素进行唯一性限制

          TreeSet:使用二叉树结构保证元素唯一,且排序

        HashSet类:

        使用哈希算法保证元素唯一!

    哈希表=数组+链表

    数组:桶(bucket),槽位(slot)

    链表:元素发生“哈希碰撞”时,继续调用equals方法,若有多个元素,就是以链表形式存在的,共享同一个槽位。

    HashSet如何保证元素的唯一性?

    即:add(Object o)的执行过程:

    1. 先调用被添加元素的hashCode()方法,返回一个Int值。通过这个值计算出一个和槽位对应的一个值。
    2. 判断对应的槽位上是否为空,为空,就说明当前元素就是第一个元素,就直接添加。不为空,说明发生了哈希碰撞,再次调用被添加元素equals方法。把已经存在的元素当成参数。
    3. 返回值为true,重复了,要填间的元素不能添加。
    4. 返回值为false,没有重复,要添加的元素以链表的形式添加到对应的槽位上。
    5. 想要被HashSet窜出的对象所在的类,必须重写hashCode()和equals方法,
    6. IDE中可以自动生成,生成的原则就是让所有的成员变量都参与到这两个方法计算中。
    7. IDE就是Integrated Develpment Eviroment,集成开发环境。

          

    • 自定义泛型类
    • 自定义泛型方法
    • 泛型匹配

    List接口总结:

    • ArrayList:底层使用的是数组存储元素,Objcet[],线程不安全,效率高。查询快增删慢。
    • LinkedList:底层使用的是链表(双向链表),查询慢,增删快。
    • Vection:底层使用的是数组存储元素,线程安全,效率低。

    如何选择:Arraylist比较通用。如果增删多选择LinkedList,Vector基本不用,已经被Arraylist替代。

    练习:

    使用LinkedList类模拟栈结构的集合。(FILO,LIFO)FIFO: First in, First out.先进先出。 LIFO: Last in, First out.(注意模拟栈结构,不是直接使用LinkedList,即:有一个集合,其中的元素是先进后出。)

    代码内容:

    1.使用ArrayList实现字符串的去重

    思路1:创建一个新的空集合,将原集合中的数据依次放到新集合中,放的同时判断:新集合中是否已经包含了这个元素,如果不包含,再添加到新集合!!!如果已经包含,就不添加
    package com.test2;
    
    import java.util.ArrayList;
    
    /*
     * 使用ArrayList实现字符串的去重
     * List : 特点:元素可重复!!!
     * 
     * 思路:
     * 创建新的集合,把原集合中的元素放到新集合中,在放的同时,进行判断:
     *     如果存在,就不添加;如果不存在,就添加.
     *     最终新集合中就是去重后的结果!!!
     * 
     */
    public class Demo {
    
        public static void main(String[] args) {
            ArrayList list = new ArrayList();
            list.add("abc");
            list.add("abc");
            list.add("java");
            list.add("java");
            list.add("java");
            list.add("def");
            list.add("mysql");
            
            //创建一个新的集合
            ArrayList list2 = new ArrayList();
            //遍历原集合,到新集合中判断:
            for (Object obj : list) {
                if(!list2.contains(obj)){
                    list2.add(obj);
                }
            }
    
            //遍历新集合
            for (Object obj : list2) {
                System.out.println(obj);
            }
            
        }
    
    }

    思路2:

    思考:不使用新集合是否能达到去重目的??
    依次遍历集合中的元素,和其后的所有元素进行比较,若碰到相等的,就删除!
    package com.test2;
    
    import java.util.ArrayList;
    
    /*
     * 使用ArrayList实现字符串的去重
     * List : 特点:元素可重复!!!
     * 
     * 思路:
     * 创建新的集合,把原集合中的元素放到新集合中,在放的同时,进行判断:
     *     如果存在,就不添加;如果不存在,就添加.
     *     最终新集合中就是去重后的结果!!!
     * 
     * 思路2:不创建新集合
     *     依次拿出集合中的元素,和其后的所有元素进行比较,如果遇到相等的,就删除 后面的元素!!
     * 
     * 如果有多个连续出现的重复元素,会发生漏删除现象!
     * 优化:
     *     > 1.遇到删除的元素后,循环变量不要自增,继续判断当前位置上的元素
     *     > 2.从后往前遍历
     *     
     * 
     */
    public class Demo {
    
        public static void main(String[] args) {
            ArrayList list = new ArrayList();
            list.add("abc");
            list.add("java");
            list.add("abc");
            list.add("abc");
            list.add("java");
            list.add("def");
            list.add("mysql");
            list.add("java");
        
            //优化1:遇到删除的元素后,循环变量不要自增,继续判断当前位置上的元素
            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--;
                    }
                }
            }
                    
            //优化2:从后往前遍历
            for(int i = 0;i<list.size()-1;i++){
                for(int j = list.size() - 1;j>i;j--){
                    if(list.get(i).equals(list.get(j))){
                        //删除后面的元素
                        list.remove(j);
                    }
                }
            }
            for (Object obj : list) {
                System.out.println(obj);
            }            
            
        }
    
    }

     3.使用数组保存10个范围在1-20之间的随机数,要求数值不能重复。

    方法一:
    public
    class Work1 { public static void main(String[] args) { //创建一个新数组 int[] arr = new int[10]; for(int i = 0;i < 10;i++){ arr[i] = (int) (Math.random() * 20 + 1);//生成随机数 for (int j = 0; j < i; j++) {//(遍历数组中储存进去的值,i中有几个值则循环几次) if (arr[j] == arr[i]) {//把储存在数组中的值j 和 随机出的值i 做比较 i--; //数组的值索引-1,i的循环次数回到上次 break; } } } for (int i : arr) { System.out.print(i + " "); }
    方法二:
    package
    com.test; import java.util.Arrays; /* * 使用数组保存10个范围在1-20之间的随机数.要求数值不能重复! */ public class RandomArrayDemo { public static void main(String[] args) { int[] arr = generateArray(5, 0, 5); System.out.println(Arrays.toString(arr)); } /** * 随机产生一个int数组. * @param length 生成数组的长度 * @param start 数组中最小值 * @param end 数组中最大值 * @return 随机的数组 */ public static int[] generateArray(int length,int start,int end){ int[] arr = new int[length]; for (int i = 0; i < arr.length; i++) { //产生随机值 int r = (int)(Math.random() * (end - start + 1) + start); //和已经存在的元素进行比较,防止默认值的元素放不进去!! for(int j = 0;j<i;j++){ if(arr[j] == r){ //重新产生随机数 r = (int)(Math.random() * (end - start + 1) + start); j=-1;//!!! i-- } } // arr[i] = r; } return arr; } }

     4.从键盘录入一个字符串,将其中以m/M之前字母开头的单词放到一个集合中,
        以m/M之后的字母开头的单词放到另一个集合中,并将两个集合元素输出.

    package com.test;
    
    import java.util.ArrayList;
    import java.util.Scanner;
    import java.util.regex.Matcher;
    import java.util.regex.Pattern;
    
    /*
     * 从键盘录入一个字符串,将其中以m/M之前字母开头的单词放到一个集合中,
        以m/M之后的字母开头的单词放到另一个集合中,并将两个集合元素输出.
     */
    public class ExtractWordsDemo {
    
        public static void main(String[] args) {
            String s =    new Scanner(System.in).nextLine();
            Matcher m1 = Pattern.compile("\b[a-lA-L]\w*\b").matcher(s);
            Matcher m2 = Pattern.compile("\b[m-zM-Z]\w*\b").matcher(s);
            
            ArrayList<String> list1 = new ArrayList<String>();
            ArrayList<String> list2 = new ArrayList<String>();
            
            while(m1.find()){
                list1.add(m1.group());
            }
            while(m2.find()){
                list2.add(m2.group());
            }
    
            for (String string : list1) {
                System.out.println(string);
            }
            
            System.out.println("---------------");
            for (String string : list2) {
                System.out.println(string);
            }
        }
    
    }

  • 相关阅读:
    Quicksum -SilverN
    uva 140 bandwidth (好题) ——yhx
    uva 129 krypton factors ——yhx
    uva 524 prime ring problem——yhx
    uva 10976 fractions again(水题)——yhx
    uva 11059 maximum product(水题)——yhx
    uva 725 division(水题)——yhx
    uva 11853 paintball(好题)——yhx
    uva 1599 ideal path(好题)——yhx
    uva 1572 self-assembly ——yhx
  • 原文地址:https://www.cnblogs.com/akinodoo/p/9937058.html
Copyright © 2011-2022 走看看