关于java的collection框架我们最应该知道的两个接口和四个实现类

/**
 * collection集合框架测试
 */
static void collectionTest() {
    /* =====================List测试====================== */

    // 五个集合,作为有参构造器的参数
    Collection<String> collection = new ArrayList<>();
    LinkedList<String> linkedListCollection = new LinkedList<>();
    ArrayList<String> arrayListCollection = new ArrayList<>();
    HashSet<String> hashSetCollection = new HashSet<>();
    TreeSet<String> treeSetSetCollection = new TreeSet<>();
  1. LinkedList

    // LinkedList
    // 空参构造器
    LinkedList<String> linkedList = new LinkedList<>();
    // 有参构造器,五个集合均可作为他的有参构造器参数
    // 有参构造器,构造一个包含指定 collection 中的元素的列表
    // 这些元素按其参数的迭代器返回的顺序排列,所以我们可以知道有参是有序的
    LinkedList<String> linkedList2 = new LinkedList<>(collection);
    LinkedList<String> linkedList3 = new LinkedList<>(linkedListCollection);
    LinkedList<String> linkedList4 = new LinkedList<>(arrayListCollection);
    LinkedList<String> linkedList5 = new LinkedList<>(hashSetCollection);
    LinkedList<String> linkedList6 = new LinkedList<>(treeSetSetCollection);
    
    linkedList = (LinkedList<String>) prepareData(linkedList);
    printResult(linkedList);
    
    // 这个方法是在末尾插入的,所以你会看到打印的末尾会出项这个字符串
    linkedList.add("wo shi pu zhen wei!");
    printResult(linkedList);
    
    // 在首位置添加,链表长度增加,已有元素向后顺移
    linkedList.addFirst("hello 双向链表集合");
    printResult(linkedList);
    
    // 在末尾增加
    linkedList.addLast("我又来了,双向链表集合!");
    printResult(linkedList);
    
    // 获取首位置,末尾
    String first = linkedList.getFirst();
    String last = linkedList.getLast();
    System.out.println("first======" + first + "============" + "last==========" + last);
    
    // 移除首位置,末尾
    linkedList.removeFirst();
    linkedList.removeLast();
    printResult(linkedList);
    
    // 从末尾增加的另一种方法,这几个方法是队列操作
    linkedList.offer("这是从哪里增加的呢?");
    linkedList.poll();
    printResult(linkedList);
    // 获得第一个的另一种方法
    first = linkedList.peek();
    System.out.println("first======" + first + "============" + "last==========" + last);
    
    if (linkedList.contains("wxyzA")) {// 必须要是某个元素,否则一直false
        int index = linkedList.indexOf("wxyzA");
        System.out.println("index==============================" + index);
    } else {
        System.out.println("index==============================找不到哦");
        System.out.println();
    }
    
    Object[] linkedListArray = linkedList.toArray();
    for (int i = 0; i < linkedListArray.length; i++) {
        System.out.println("linkedListArray===========" + linkedListArray[i]);
    }
    
    String[] linkedString = new String[] {};
    Object[] lArray = linkedList.toArray(linkedString);
    for (int i = 0; i < lArray.length; i++) {
        System.out.println("lArray===========" + lArray[i]);
    }
    
  2. ArrayList测试

    // ArrayList测试
    // 无参构造器,构造一个初始容量为 10 的空列表
    ArrayList<String> aList = new ArrayList<>();
    // 有参构造器,五个集合均可作为他的有参构造器参数
    // 有参构造器,构造一个包含指定 collection 中的元素的列表
    // 这些元素按其参数的迭代器返回的顺序排列,所以我们可以知道有参是有序的
    ArrayList<String> aList2 = new ArrayList<>(collection);
    ArrayList<String> aList3 = new ArrayList<>(linkedListCollection);
    ArrayList<String> aList4 = new ArrayList<>(arrayListCollection);
    ArrayList<String> aList5 = new ArrayList<>(hashSetCollection);
    ArrayList<String> aList6 = new ArrayList<>(treeSetSetCollection);
    
    // 有参,指定容量
    ArrayList<String> aList7 = new ArrayList<>(100);
    
    aList = (ArrayList<String>) prepareData(aList);
    printResult(aList);
    
    // 其他方法与LinkedList一模一样,但是没有两端操作数据的方法而已
    // 一般的,我们都是使用ArrayList,但是如果有两端操作的话就使用LinkedList
    aList.add("wo shi pu zhen wei!");
    aList.remove(10);
    if (aList.contains("ABCDE")) {
        int index = linkedList.indexOf("ABCDE");
        if (index < 58) {
            // 分割list
            List<String> list = aList.subList(index + 1, index + 2);
            printResult(list);
        }
        System.out.println("index==============================" + index);
    } else {
        System.out.println("index==============================找不到哦");
        System.out.println();
    }
    
    if (aList.contains("ABCDE")) {
        boolean success = aList.remove("ABCDE");
        if (success) {
            System.out.println("success==============================" + success);
        } else {
            System.out.println("success==============================" + success);
            System.out.println();
        }
    }
    
    // 使用不指定类型时,既可以使用Object作为数组引用
    // 也可以为数组引用指定类型,只要强转就可以了,但是
    // 类型可定要与set的泛型一直才能转换
    Object[] aListArray = aList.toArray();
    // String[] aListArray = (String[]) aList.toArray();// 强转
    for (int i = 0; i < aListArray.length; i++) {
        System.out.println("aListArray===========" + aListArray[i]);
    }
    
    // 使用直接指定类型的API
    String[] aListString = new String[] {};
    String[] aListArray2 = aList.toArray(aListString);
    for (int i = 0; i < aListArray2.length; i++) {
        System.out.println("aListArray===========" + aListArray2[i]);
    }
    /* =====================List测试结束====================== */
    
    /* =======================set测试========================= */
    
  3. HashSet

    // hashSet测试
    // 空参,构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75
    // 加载因子是什么,在后面有解释哦,并且告诉你什么是哈希算法哦
    HashSet<String> hashSet = new HashSet<>();
    // 有参构造器,五个集合均可作为他的有参构造器参数
    // 有参构造器,构造一个包含指定 collection 中的元素的列表
    // 这些元素按其参数的迭代器返回的顺序排列,所以我们可以知道有参是有序的
    HashSet<String> hashSet2 = new HashSet<>(collection);
    HashSet<String> hashSet3 = new HashSet<>(linkedListCollection);
    HashSet<String> hashSet4 = new HashSet<>(arrayListCollection);
    HashSet<String> hashSet5 = new HashSet<>(hashSetCollection);
    HashSet<String> hashSet6 = new HashSet<>(treeSetSetCollection);
    
    // 另外两个有参构造器
    // 指定容量,不指定加载因子
    HashSet<String> hashSet7 = new HashSet<>(32);
    // 指定容量,并且指定加载因子,加载因子是float类型的哦
    // 所以注意要加float的标识,java默认是double
    HashSet<String> hashSet8 = new HashSet<>(32, 0.5f);
    
    hashSet = (HashSet<String>) prepareData(hashSet);
    printResult(hashSet);
    Iterator<String> it = hashSet.iterator();
    while (it.hasNext()) {
        System.out.println("it.next============" + it.next());
    }
    
    // 清空set
    hashSet.clear();
    
    // 添加元素,还有addAll直接添加一个集合进来,参数是集合
    hashSet.add("wo shi pu zhen wei");
    hashSet.add("wo shi pu zhen wei // wo shi pu zhen wei");
    
    // 获取迭代器
    Iterator<String> iterator = hashSet.iterator();
    // 开始迭代
    while (iterator.hasNext()) {
        System.out.println("第二次迭代数据会变化么?============" + iterator.next());
    }
    System.out.println("===========================================================================");
    
    Iterator<String> iterator2 = hashSet.iterator();
    while (iterator2.hasNext()) {
        System.out.println("第二次迭代数据会变化么?============" + iterator2.next());
    }
    
    HashSet<String> hashSetSet = new HashSet<>();
    hashSetSet.add("wo shi pu zhen wei");
    // hashSetSet.add("wo cai shi pu zhen wei");
    if (hashSet.contains("wo shi pu zhen wei")) {
        // 注意:当一个set调用retainAll方法只能重新包含的集合
        // 是它自己的子集,否则不会包含并且该set被清空
        hashSet.retainAll(hashSetSet);
        System.out.println("hashSetSet只能是hashSet的子集么?");
        printResult(hashSet);
    }
    
    // containsAll如果此 set 包含指定 collection 的所有元素,则返回 true
    // 也就是说如果一个集合调用了这个containsAll,如果返回true,那么参数集合就是该集合的子集
    if (hashSet.containsAll(hashSetSet)) {
        System.out.println("hashSetSet是hashSet的子集");
    }
    
    // 转为数组,一个指定类型,一个不指定
    Object[] hashSetArray = hashSet.toArray();
    for (int j = 0; j < hashSetArray.length; j++) {
        System.out.println("hashSetArray===============" + hashSetArray[j]);
    }
    // 为数组指定类型,不能使用type = null,否则得不到数组,必须new
    // 也就是说type必须指向一个具有具体类型的实例才能真正作为数组类型的指定
    String[] type = new String[] {};
    String[] hashSetArray2 = hashSet.toArray(type);
    for (int j = 0; j < hashSetArray2.length; j++) {
        System.out.println("hashSetArray2===============" + hashSetArray2[j]);
    }
    

    3.1. 哈希算法

    /* ===========================哈希算法和加载因子======================================= */
    // 要理解到hashSet的加载因子(也叫负载率或者负载因子),首先我们要理解到什么是hash算法
    // 所谓hash算法就是如下的流程,在我看来,算法就是逻辑:
    // hash算法分为两部分,放入数据和取出数据
    // 放入数据
    // ---------------------------------
    // 1.调用 key.hashCode() 获得哈希值
    // 2.用哈希值计算下标值 index
    // 3.如果达到一定负载率,容量翻倍
    // 4.新建 Entry 对象来封装 key 和 value
    // 5.将 Entry 对象放入 index 位置(6,7)
    // |----6.空位置,直接放入
    // |----7.有数据,依次与每个键用 equals()方法比较是否相等(8,9)
    // -----|----8.找到相等的,覆盖值
    // -----|----9.找不到相等的,用链表连在一起
    
    // 获取数据
    // ---------------------------------
    // 1.调用 key.ohashCode() 获得哈希值
    // 2.用哈希值计算下标值 index
    // 3.依次用 equals() 方法比较键是否相等
    // |----4.找到相等的,返回它的值
    // |----5.找不到相等的,返回 null
    
    // 所以我们上面提到的加载因子,就是获取数据中的第3步的负载率
    // 比如,如果放满的位置超过默认的0.75(放满的占总数的比例),容量就会翻倍
    // 所以由此我们可知:
    // 1.加载因子越大,内存使用率越高
    // 2.加载因在越小,内存九月浪费
    // 3.但是不是说加载因在越大,就越好,加载因子越大,内存占用就越大
    // 4.所以在自定义加载因子是,最好事先计算好自己的加载因子,要不然就默认
    /* ===========================哈希算法和加载因子======================================= */
    
  4. TreeSet测试

    // TreeSet测试,TreeSet底层是二叉树,add和addAll就不测试了,这太常用了
    // 无参构造器,构造一个新的空 set,该 set 根据其元素的自然顺序进行排序
    TreeSet<String> treeSet = new TreeSet<>();
    // 有参构造器,五个集合均可作为他的有参构造器参数
    // 有参构造器,构造一个包含指定 collection 中的元素的列表
    // 这些元素按其参数的迭代器返回的顺序排列,所以我们可以知道有参是有序的
    TreeSet<String> treeSet2 = new TreeSet<>(collection);
    TreeSet<String> treeSet3 = new TreeSet<>(linkedListCollection);
    TreeSet<String> treeSet4 = new TreeSet<>(arrayListCollection);
    TreeSet<String> treeSet5 = new TreeSet<>(hashSetCollection);
    TreeSet<String> treeSet6 = new TreeSet<>(treeSetSetCollection);
    
    // 根据比较器构造一个有序的treeSet集合
    // TreeSet(Comparator<? super E> comparator)
    // 构造一个新的空 TreeSet,它根据指定比较器进行排序
    // 这个接口是需要自己去实现的,实现compare(),在这个方法中定义自己的比较规则
    
    // TreeSet实现了SortedSet接口,可以直接使用TreeSet构造器来获取一个实例
    SortedSet<String> sortedSet = new TreeSet<>();
    // 有参构造器,构造一个与指定有序 set 具有相同映射关系和相同排序的新 TreeSet
    TreeSet<String> treeSet7 = new TreeSet<>(sortedSet);
    
    treeSet = (TreeSet<String>) prepareData(treeSet);
    printResult(treeSet);
    
    // 返回大于等于给定元素的很多元素中最小的那个元素,如果不存在这些元素,则返回null
    String ceiling = treeSet.ceiling("ABCDE");
    System.out.println("ceiling============" + ceiling);
    
    // 返回对此 set 中的元素进行排序的比较器;如果此 set 使用其元素的自然顺序,则返回 null
    Comparator<? super String> comparator = treeSet.comparator();
    System.out.println("comparator============" + comparator);
    
    // set中是否包含, 还有一个containsAll(),是否包含一个集合中的所有元素
    if (treeSet.contains("ABCDE")) {
        System.out.println("包含哦=============" + treeSet.contains("ABCDE"));
    }
    
    // 返回treeSet集合按照降序进行迭代的迭代器
    // 默认迭代同样是调用iterator()方法即可获得
    Iterator<String> itDescending = treeSet.descendingIterator();
    while (itDescending.hasNext()) {
        System.out.println("降序排列====================" + itDescending.next());
    }
    
    // 返回此 set 中当前第一个(最低)元素,最低是说处于二叉树的最低
    String firstElement = treeSet.first();
    // 获取并移除第一个(最低)元素;如果此 set 为空,则返回 null
    String pollFirst = treeSet.pollFirst();
    // 返回此 set 中当前最后一个(最高)元素,最高是说处于二叉树的最高
    String lastElement = treeSet.last();
    // 获取并移除最后一个(最高)元素;如果此 set 为空,则返回 null
    String pollLast = treeSet.pollLast();
    System.out.println("最低元素是啥?====================" + firstElement);
    System.out.println("移除的最低元素是啥?====================" + pollFirst);
    System.out.println("最高元素是啥?====================" + lastElement);
    System.out.println("移除的最高元素是啥?====================" + pollLast);
    // 判断是否移出,打印一下所有,或者对比一下前后size即可,打印所有是最确保的
    printResult(treeSet);
    
    // 当然还有remove()方法,用来移除指定元素,前提是指定元素要存在哦
    boolean removeElement = treeSet.remove("ABCDE");
    if (removeElement) {
        System.out.println("移除成功啦!");
    }
    
    // 返回此set中小于等于给定元素的最大元素;如果不存在这样的元素,则返回 null
    String maxFloor = treeSet.floor("BCDEF");
    System.out.println("小于等于给定元素的最大值====================" + maxFloor);
    
    // 返回此set中元素严格小于给定元素的部分视图,也就是子集
    SortedSet<String> headSet = treeSet.headSet("ABCDE");
    // 1.如果第二个参数为false,返回此set中元素严格小于给定元素的部分视图,也就是子集
    // 2.如果第二个参数为true,返回小于等于给顶元素的部分视图
    SortedSet<String> headSet2 = treeSet.headSet("BCDEF", true);
    
    // 返回此 set 的部分视图,其元素大于等于给定元素
    SortedSet<String> tailSet = treeSet.tailSet("ABCDE");
    // 1.如果第二个参数为false,返回此set中元素严格大于给定元素的部分视图,也就是子集
    // 2.如果第二个参数为true,返回大于等于给顶元素的部分视图
    SortedSet<String> tailSet2 = treeSet.tailSet("ABCDE", true);
    
    // 返回严格大于给定元素的多有元素中最小的那个元素,如果不存在这样的元素,则返回 null
    String minHeigher = treeSet.higher("BCDEF");
    // 返回此 set 中严格小于给定元素的最大元素;如果不存在这样的元素,则返回 null
    String maxLower = treeSet.lower("BCDEF");
    
    System.out.println("严格小于给定元素的部分视图是什么?====================" + headSet);
    System.out.println("自定义是否严格小于给定元素的视图是什么?====================" + headSet2);
    System.out.println("大于等于给定元素的部分视图是什么?====================" + tailSet);
    System.out.println("自定义是否严格大于给定元素的视图是什么?====================" + tailSet2);
    System.out.println("严格大于最小元素是什么?====================" + minHeigher);
    System.out.println("严格小于最大元素是什么?====================" + maxLower);
    
    // 上面的返回的分割集合有局限性,下面我们看看完全自定义的获取子视图的方法 subSet()
    // 返回此 set 的部分视图,其元素从 fromElement(包括)到 toElement(不包括)
    SortedSet<String> subSet = treeSet.subSet("ABCDE", "abcde");
    // 自己指定包不包括,1.true包括,2.false不包括
    // 其实跟进代码会看到第一个方法是调用了第二个方法的
    SortedSet<String> subSet2 = treeSet.subSet("ABCDE", true, "abcde", true);
    System.out.println("前包后不包的子视图是什么?====================" + subSet);
    System.out.println("自定义包不包的子视图是什么?====================" + subSet2);
    /* =======================set测试结束========================= */
    }
    
    /*
     * 为List集合准备数据
     */
    static List<String> prepareData(List<String> list) {// 利用父类引用来接受数据,可以接受任意子类
        String string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for (int i = 0; i < string.length(); i++) {
            // 随机产生0-61以内的数据
            int max = 61;
            int min = 0;
            Random random = new Random();
            int rand = random.nextInt(max) % (max - min + 1) + min;
            String mathString = null;
            // 确保下标不溢出,我这里的数字是为了让每一个元素的个数为5才这样写的,你可以自己定义
            if (rand <= string.length() - 6) {
                mathString = string.substring(rand, rand + 5);
            } else {
                mathString = string.substring(rand - 5, rand);
            }
            list.add(mathString);
        }
        return list;
    }
    
    /**
     * 为set集合准备数据
     * 
     * @param set
     * @return
     */
    static Set<String> prepareData(Set<String> set) {
        String string = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        for (int i = 0; i < string.length(); i++) {
            // 随机产生0-61以内的数据
            int max = 61;
            int min = 0;
            Random random = new Random();
            int rand = random.nextInt(max) % (max - min + 1) + min;
            String mathString = null;
            // 确保下标不溢出,我这里的数字是为了让每一个元素的个数为5才这样写的,你可以自己定义
            if (rand <= string.length() - 6) {
                // 用获得的随机数来作为下标,每次随机截取5个字符,作为一个元素
                mathString = string.substring(rand, rand + 5);
            } else {
                mathString = string.substring(rand - 5, rand);
            }
            set.add(mathString);
        }
        return set;
    }
    
    /**
     * 打印结果
     * 
     * @param list
     */
    static void printResult(List<String> list) {
        int size = list.size();
        // 我们来打印一下这个链表集合,以及它的总数,肯定是62
        System.out.println("size ============================================ " + size);
        for (int i = 0; i < list.size(); i++) {
            System.out.println("这里的List =================== " + list.get(i));
        }
        System.out.println();
    }
    
    /**
     * 打印结果
     * 
     * @param set
     */
    static void printResult(Set<String> set) {
        int size = set.size();
        // 我们来打印一下这个set集合,以及它的总数
        // 由于set不可重复,所以set的size有可能会小于62
        System.out.println("size ============================================ " + size);
        Iterator<String> it = set.iterator();
        while (it.hasNext()) {
            String setString = it.next();
            System.out.println("这里的set =================== " + setString);
        }
        System.out.println();
    }
    
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值