/**
* 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();
}