Java进阶九—数组问题(集合框架)
一.原生数组带来的问题
- 原生数组容易造成超出边界,如果非要使用传统的数组,增删改查,就要用到数据结构,非常复杂
- CRUD是指在做计算处理时的增加(Create)、读取查询(Retrieve)、更新(Update)和删除(Delete)几个单词的首字母简写
package com.array;import org.junit.Test;public class ArrayTest {public static final int SIZE = 3;@Testpublic void testArray() {int[] array = new int[SIZE];array[0] = 1;array[1] = 2;array[2] = 3;array[3] = 4;for (int arrays :array) {System.out.println(arrays);}} }
由此我们抛出Java Conllections FrameWork即Java集合框架,也可称为函数库
二.Conllections家族
- Java集合框架是一个包含一系列实作可重复使用集合的数据结构的类别和界面集合
- Java集合大致可以分为两大体系,一个是
Collection
,另一个是Map
三. 黑帮的帮规
集合 (Java Platform SE 8) (oracle.com)
lterables
集合层次结构中的根接口,可以理解为保护伞- 一般黑老大不会自己出手,会让手下三个组织来办事,所以用的时候找类来实现
- 黑老大定下的规矩(方法),手下三个组织必须遵守。其实就是Collection的方法,实现的三个接口List,Queue,Set必须重写方法。
四.ArrayList
ArrayList (Java Platform SE 8 ) (oracle.com)
ArrayList
类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。
ArrayList
继承了 AbstractList
,并实现了 List
接口可以自动扩容
1.添加
这个E代表泛型,表示任意变量类型。
public void arrayListTest() {// 任意类型ArrayList arrayList = new ArrayList();arrayList.add(1);arrayList.add(4.3);arrayList.add("C");arrayList.add("fuck");System.out.println(arrayList);// 规定为String类型,泛型限定ArrayList<String> arrayList1 = new ArrayList<>();arrayList1.add("fu");arrayList1.add("ck");System.out.println(arrayList1);}
泛型也可以是对象,创建一个Student
类
package com.array;public class Student {private String name;private int age;public Student() {}public Student(String name,int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
public void arrayListTest() {// 泛型为StudentArrayList<Student> arrayList = new ArrayList<>();arrayList.add(new Student("fuck",22));arrayList.add(new Student("LiLi",33));System.out.println(arrayList);}
还有一种添加可以指定下标位置。
public void arrayListTest() {// 泛型为整数与浮点数时要使用他们的包装类ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(3);// 添加下标时,要注意添加的位置,添加的位置已有的位置前或中间,不能是后面。arrayList.add(0,0);arrayList.add(2,2);System.out.println(arrayList);}
2.合并
public void arrayListTest() {// 泛型为整数与浮点数时要使用他们的包装类ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(3);// 添加下标时,要注意添加的位置,添加的位置已有的位置前或中间,不能是后面。arrayList.add(0,0);arrayList.add(2,2);ArrayList<Integer> arrayList1 = new ArrayList<>();arrayList1.add(4);// 将arrayList1合并到arrayListarrayList.addAll(arrayList1);System.out.println(arrayList);}
它是如何实现的,看源码
集合转换成普通数组,拷贝数组并返回。
第二种是选择下标插入,非常简单与添加使用的方式一样,我应该不用说了。
3.将集合转换成数组
public void arrayListTest() {// 泛型为整数与浮点数时要使用他们的包装类ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);arrayList.add(4);// 需要Object类型的数组去接收Object[] array = arrayList.toArray();for (int i = 0; i < array.length; i++) {System.out.println(array[i]);}}
4.清空与拷贝
public void arrayListTest() {// 泛型为整数与浮点数时要使用他们的包装类ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);arrayList.add(4);System.out.println(arrayList);// 清空arrayList.clear();System.out.println(arrayList);}
public void arrayListTest() {// 泛型为整数与浮点数时要使用他们的包装类ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);arrayList.add(4);System.out.println(arrayList);ArrayList<Integer> arrayList1 = (ArrayList<Integer>) arrayList.clone();// 拷贝System.out.println(arrayList1);}
5. 查看集合中是否有这个元素
public void arrayListTest() {// 泛型为整数与浮点数时要使用他们的包装类ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);arrayList.add(4);// 返回boolean类型boolean number1 = arrayList.contains(3);System.out.println(number1);boolean number2 = arrayList.contains(5);System.out.println(number2);}
6. 获取集合的容量与需要的下标值,与任何遍历
集合之所以可以直接输出不用遍历,是因为它重新了toString方法。
public void arrayListTest() {// 泛型为整数与浮点数时要使用他们的包装类ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);arrayList.add(4);// 集合容量System.out.println(arrayList.size());// 下标为2的值int indexTwo = arrayList.get(2);System.out.println(indexTwo);// 遍历,并给每一个元素加2,// 遍历的作用:不仅要输出,还有操作// 方法一:for循环数组遍历时使用length,而集合遍历使用sizefor (int i = 0; i < arrayList.size(); i++) {System.out.print(arrayList.get(i)+2+"\t");}System.out.println();// 方法二:增强for循环for (Integer value : arrayList) {System.out.print(value+2+"\t");}
7. 给值找下标
public void arrayListTest() {ArrayList<String> arrayList = new ArrayList<>();arrayList.add("Man");arrayList.add("Tom");arrayList.add("Fuck");arrayList.add("LiLi");arrayList.add("Fuck");arrayList.add("JiJi");// 从前往后,查找最近的System.out.println(arrayList.indexOf("Fuck"));// 从后往前,查找最近的System.out.println(arrayList.lastIndexOf("Fuck"));}
8. 查看集合是否为空
public void arrayListTest() {ArrayList<String> arrayList = new ArrayList<>();arrayList.add("Man");arrayList.add("Tom");arrayList.add("Fuck");// 集合是否为空System.out.println(arrayList.isEmpty());ArrayList<String> arrayList1 = new ArrayList<>();// 集合是否为空System.out.println(arrayList1.isEmpty());}
9. 删除
public void arrayListTest() {ArrayList<String> arrayList = new ArrayList<>();arrayList.add("Man");arrayList.add("Tom");arrayList.add("Fuck");arrayList.add(null);System.out.println(arrayList);// 指定值删除,删除值为空的System.out.println(arrayList.remove(null));System.out.println(arrayList);}
public void arrayListTest() {ArrayList<String> arrayList = new ArrayList<>();arrayList.add("Man");arrayList.add("Tom");arrayList.add("Fuck");arrayList.add(null);System.out.println(arrayList);// 指定下标删除,删除值为空的System.out.println(arrayList.remove(3));System.out.println(arrayList);}
public void arrayListTest() {ArrayList<String> arrayList = new ArrayList<>();arrayList.add("Man");arrayList.add("Tom");arrayList.add("Fuck");arrayList.add(null);System.out.println(arrayList);ArrayList<String> arrayList1 = new ArrayList<>();arrayList1.add("Fuck");arrayList1.add(null);// 根据arrayList1集合元素删除arrayList里的相同元素arrayList.removeAll(arrayList1);System.out.println(arrayList);}
10.两个集合取交集(相同元素)
public void arrayListTest() {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);System.out.println(arrayList);ArrayList<Integer> arrayList1 = new ArrayList<>();arrayList1.add(3);arrayList1.add(5);System.out.println(arrayList1);// 取交集System.out.println(arrayList.retainAll(arrayList1));// 原理是取完交集后,放在arrayList中System.out.println(arrayList);}
11. 替换
public void arrayListTest() {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(1);arrayList.add(2);arrayList.add(3);System.out.println(arrayList);// 把3替换成4arrayList.set(2,4);System.out.println(arrayList);}
12.排序与倒序
由于此方法要使用拉姆达表达式,使用我们采用另一种方法。
集合 (Java Platform SE 8 ) (oracle.com)
public void arrayListTest() {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(7);arrayList.add(4);arrayList.add(0);arrayList.add(44);System.out.println(arrayList);// 排序,从小到大Collections.sort(arrayList);System.out.println(arrayList);// 倒序Collections.reverse(arrayList);System.out.println(arrayList);}
13.取指定下标范围的值
public void arrayListTest() {ArrayList<Integer> arrayList = new ArrayList<>();arrayList.add(7);arrayList.add(4);arrayList.add(0);arrayList.add(44);System.out.println(arrayList);// 查找下标1到3的值;System.out.println(arrayList.subList(1,4));// 之所以下标是1-4是因为,这个查找原理是这样的:1 <= 下标范围 < 4}
五.Linked链表
ArrayList
数组集合,增删慢,查询快LinkedList
链表集合,增删快,查询慢
数组集合之所以增删慢,是因为增删时集合内元素要移动
链表集合增删快,是因为链表集合增删时内部元素不需要移动
六.LinkedList一带而过
- 链表是数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的地址
- 链表可分为单向链表和双向链表
- 由于黑老大定下的规矩,所以它跟ArrayList方法差不多相同。
LinkedList (Java Platform SE 8 ) (oracle.com)
七.iterator 迭代器初试
- 迭代是重复反馈过程的活动,其目的通常是为了接近并到达所需目标或结果
- 每一次对过程的重复被称为一次“迭代”,而每一次迭代的结果会被用来作为下一次迭代的初始值
迭代器Iterator用于
Conllections家族 ,不管用于ArrayList
还是LinkedList
都可以迭代输出
public void arrayListTest() {// 数组集合ArrayList<String> arrayList = new ArrayList<>();arrayList.add("Tom");arrayList.add("Fuck");arrayList.add("Lise");// 使用方式Iterator<String> iterator = arrayList.iterator();// hasNext()判断是否有值while (iterator.hasNext()) {String value = iterator.next();System.out.println(value);}}
public void arrayListTest() {// 链表集合LinkedList<String> linkedList = new LinkedList<>();linkedList.add("Tom");linkedList.add("Fuck");linkedList.add("Lise");// 使用方式Iterator<String> iterator = linkedList.iterator();// hasNext()判断是否有值while (iterator.hasNext()) {String value = iterator.next();System.out.println(value);}}
八.fori、增强for、迭代器的区别、谈谈三者性能
for循环
适合数据的读取与修改- 增强for循环适合数据的读取
Iterator
不要使用for循环嵌套使用,适合数据的读取与修改public void arrayListTest() {// 链表集合LinkedList<String> linkedList = new LinkedList<>();linkedList.add("Tom");linkedList.add("Fuck");linkedList.add("Lise");// 使用方式Iterator<String> iterator = linkedList.iterator();// hasNext()判断是否有值while (iterator.hasNext()) {String value = iterator.next();// 删除Tomif (value.equals("Tom")) {// 要使用iterator自带的remove()方法iterator.remove();}}System.out.println(linkedList);}
增强for循环是一个小型的迭代器了,如果一定要在增强for循环中修改集合的话可以使用迭代器,但不建议在增强for循环中直接修改
谈谈三者性能:比较时间复杂度
如果是 ArrayList ,用三种方式遍历的速度是for循环>Iterator>增强for循环,速度级别基本一致,一般都会用for循环或者增强for循环,因为Iterator写法相对复杂一些
如果是 LinkedList,则三种方式遍历的差距很大了,数据量大时越明显,Iterator>增强for循环>>>for循环,推荐使用增强for循环或者Iterator
List遍历:for,foreach Iterator 速度比较_list迭代器遍历执行慢-CSDN博客
九.Set和HashSet
HashSet
基于 HashMap
来实现的,是一个不允许有重复元素的集合,允许有 null 值,是无序的,即不会记录插入的顺序。
public void setTest() {// 使用Hash函数实现HashSet,元素无序,且不重复HashSet<String> hashSet = new HashSet<>();hashSet.add("Tom");hashSet.add("Fuck");hashSet.add("LiLi");hashSet.add("LiLi");hashSet.add("Fuck");System.out.println(hashSet);// 之所以输出后没有顺序且是唯一,是由于hashSet的每一个元素都会给应该hash值// hash值相当与身份证,不重复是唯一的}
关于Java的Hash算法的深入理解-CSDN博客
十.LinkedHashSet
如果要创建有序集合呢?LinkedHashSet
便是有序的不重复的
public void setTest() {LinkedHashSet<String> linkedHashSet = new LinkedHashSet<>();linkedHashSet.add("Tom");linkedHashSet.add("Fuck");linkedHashSet.add("LiLi");linkedHashSet.add("LiLi");linkedHashSet.add("Fuck");System.out.println(linkedHashSet);}
十一.Map、HashMap、Entry
HashMap (Java Platform SE 8 ) (oracle.com)
public void mapTest() {// 有两个泛型:第一个为key(钥匙),第二个为value(值)HashMap<Integer,String> hashMap = new HashMap<>();hashMap.put(10000000,"Fuck");hashMap.put(10000001,"Tom");hashMap.put(10000002,"LiLi");hashMap.put(10000003,"Man");System.out.println(hashMap);// 1.输出编号为10000000的人String value = hashMap.get(10000000);System.out.println(value);// 2.删除编号10000001的人hashMap.remove(10000001);System.out.println(hashMap);// 3.是否包含编号为10000002的人与叫Fuck的人System.out.println(hashMap.containsKey(10000002));System.out.println(hashMap.containsValue("Fuck"));// 4.替换编号为10000003的人的名字为DoghashMap.replace(10000003,"Dog");System.out.println(hashMap);// 5.保存编号Set<Integer> keys = hashMap.keySet();System.out.println(keys);// 6.保存编号与名字Set<Map.Entry<Integer, String>> entrySet = hashMap.entrySet();System.out.println(entrySet);}
已经存在的键值对,再次.put()
会替换原来的,.get()
不存在的值会返回null
十二. Entry与Map转换Set之后遍历: Iterator<Entry<Integer,Integer>> iterator = entrySet.iterator();
- 之所以使用Entry把Map转换Set是因为之后方便遍历
Entry
就是用来管理键值对对象的,将对象包裹起来,提供遍历的方式Entry
可以使用迭代器,筛选值,但只适合在内存中使用,不适用于JDBC
public void MapTest() {HashMap<Integer,Integer> hashMap = new HashMap<>();System.out.println("学生准考证号与成绩");hashMap.put(10000000,88);hashMap.put(10000001,49);hashMap.put(10000002,53);hashMap.put(10000003,83);hashMap.put(10000004,71);System.out.println(hashMap);System.out.println("80分以上的分数");// 使用Set保存学生准考证号与成绩方便遍历Set<Map.Entry<Integer,Integer>> entrySet = hashMap.entrySet();// 使用ArrayList保存80分以上的分数ArrayList<Integer> arrayList = new ArrayList<>();// 迭代器的泛型是Map.Entry<Integer,Integer>不要出错Iterator<Map.Entry<Integer,Integer>> iterator = entrySet.iterator();while (iterator.hasNext()) {// 取出学生成绩放入vaLueint value = iterator.next().getValue();// 判断80分以上的分数if (value > 80) {arrayList.add(value);}}System.out.println(arrayList);}
十三.LinkedHashMap
HashMap
是无序的,可以自定义泛型,而LinkedHashMap
相当于有序的HashMap
LinkedHashMap (Java Platform SE 8 ) (oracle.com)
十四.集合框架部分结束
剩下的类需要自己去学习了!了解各类是怎么实现的,以及其之间的区别,JDK的新特性暂时用不到,还没学习到框架