/**
* 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<>();
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]); }
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测试========================= */
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.所以在自定义加载因子是,最好事先计算好自己的加载因子,要不然就默认 /* ===========================哈希算法和加载因子======================================= */
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(); }