当前位置: 首页 > news >正文

day06-集合-CollectionListSet

一、集合

Collection集合特点:

  • list系列集合:有序、可重复

    • ArrayList、LinekdList

  • Set系列集合:无序、不重复

    • HashSet

    • LinkedHashSet:存取有序

    • TreeSet:可排序

1.1 Collection的常见方法

Collection<E> 这是单列集合的根接口boolean add(E e) 添加元素boolean remove(E e) 删除指定的元素 (如有重复删除第一个)boolean contains(Object obj) 判断集合中是否包含指定元素int size() 返回集合中元素的个数boolean isEmpty() 判断集合是否为空Object[] toArray() 将集合中元素存入一个对象数组并返回T[] toArray(T[]a)  将集合中元素存入一个指定类型的数组并返回(指定数组长度)void clear() 清空集合void addAll(集合) 添加另外一个集合中的元素
public class Demo2 {public static void main(String[] args) {//多态创建单列集合Collection<String> coll = new ArrayList<>();//boolean add(E e) 添加元素coll.add("下雨");coll.add("下雪");coll.add("刮风");coll.add("刮风");System.out.println(coll);
​//boolean remove(E e) 删除指定的元素 (如有重复删除第一个)coll.remove("刮风");System.out.println(coll);
​//boolean contains(Object obj) 判断集合中是否包含指定元素boolean contains = coll.contains("下雪");System.out.println("contains=" + contains);
​//int size() 返回集合中元素的个数int size = coll.size();System.out.println("size=" + size);
​//boolean isEmpty() 判断集合是否为空boolean empty = coll.isEmpty();System.out.println("empty=" + empty);//空-->true;否则-->false
​//Object[] toArray() 将集合中元素存入一个对象数组并返回Object[] objects = coll.toArray();System.out.println(Arrays.toString(objects));
​//T[] toArray(T[]a)  将集合中元素存入一个指定类型的数组并返回(指定数组长度)String[] strings = coll.toArray(new String[coll.size()]);System.out.println(Arrays.toString(strings));
​//void clear() 清空集合coll.clear();System.out.println(coll);
​}
}
运行结果:
[下雨, 下雪, 刮风, 刮风]
[下雨, 下雪, 刮风]
contains=true
size=3
empty=false
[下雨, 下雪, 刮风]
[下雨, 下雪, 刮风]
[]

1.2 Collection的遍历方式

1.2.1 迭代器Iterator

遍历1: 迭代器Iterator(不回头,用完需要重现创建)单列集合专用遍历方式
​
Iterator相关方法Iterator<E> iterator() 获取迭代器对象,默认指向第一个元素boolean hasNext() 断当前位置是否有元素可以取出 (有返回true,没有返回false)E next() 返回当前位置的元素,并将送代器后移一位(如果没有元素可以取出了还继续取,会报NoSuchElementException)
​
固定格式Iterator<String> iterator  = list.iterator();while (iterator.hasNext()) {String s = iterator.next();}
public class Demo3 {public static void main(String[] args) {//1. 准备一个集合Collection<String> collection = new ArrayList<>();collection.add("java");collection.add("python");collection.add("c++");collection.add("c#");
​//2. 获取迭代器对象Iterator<String> iterator = collection.iterator();//3. 使用迭代器遍历while(iterator.hasNext()){String s = iterator.next();System.out.println(s);}}
}

1.2.2 增强for

遍历2: 增强for循环数组和集合都可以使用
​
相关格式for(元素数据类型 变量名 : 数组或者集合){操作变量}
​
注意1. 在增强for循环中修改数据, 是不会影响数据源的(底层会创建临时变量,来记录容器中的数据)2. 增强for遍历集合,底层是迭代器遍历集合的逻辑3. 增强for遍历数组,底层是普通for循环的逻辑
public class Demo4 {public static void main(String[] args) {//1. 准备一个集合Collection<String> collection = new ArrayList<>();collection.add("java");collection.add("python");collection.add("c++");collection.add("c#");
​//2. 使用增强for循环遍历for (String s : collection) {System.out.println(s);}
​
​
​//增强for循环也可以遍历数组int[] arr = {1,2,3};for (int i : arr) {System.out.println(i);}}
}

1.2.3 Lambda表达式方式

遍历3: Lambda表达式方式遍历集合
​
相关格式collection.forEach(e -> {System.out.println(e);});
public class Demo5 {public static void main(String[] args) {//1. 准备一个集合Collection<String> collection = new ArrayList<>();collection.add("java");collection.add("python");collection.add("c++");collection.add("c#");
​//2. Lambda表达式方式遍历集合collection.forEach((e)->{//遍历集合中的元素eSystem.out.println(e);});
​}
}

1.3 删除集合元素

问题使用迭代器遍历集合时,又同时在删除集合中的数据,程序就会出现并发修改异常的错误。由于增强for循环遍历集合就是迭代器遍历集合的简化写法,因此,使用增强for循环遍历集合,又在同时删除集合中的数据时,程序也会出现并发修改异常的错误
​
解决方法迭代器: 用迭代器自己的删除方法删除数据即可(iterator.remove();)增强for循环: 暂时无法解决普通for循环(需要有索引):可以倒着遍历并删除;或者从前往后遍历,但删除元素后做(i--)操作。
public class Demo7 {public static void main(String[] args) {//1. 准备一个集合ArrayList<String> arrayList = new ArrayList<>();arrayList.add("Java入门");arrayList.add("宁夏枸杞");arrayList.add("黑枸杞");arrayList.add("人字拖");arrayList.add("特级枸杞");arrayList.add("枸杞子");
​//使用迭代器方式,删除所有带枸杞的Iterator<String> iterator = arrayList.iterator();while(iterator.hasNext()){//获取元素String str = iterator.next();if(str.contains("枸杞")){//通过迭代器删除iterator.remove();//从迭代器中删除当前元素}}System.out.println(arrayList);//[Java入门, 人字拖]}
}

1.4 集合存储对象的原理

二、List集合

2.1 List集合常用方法

List系列集合的特点 有序的, 可重复List集合支持索引,所以提供了很多通过索引操作元素的方法void add(int index,E e) 在此集合中的指定位置插入指定的元素E remove(int index) 删除指定索引处的元素,返回被删除的元素 (一般不接收)E set(int index,E e) 修改指定索引处的元素,返回被修改的元素(一般不接收)E get(int index) 返回指定索引处的元素
public class Demo1 {public static void main(String[] args) {//多态方式创建list集合List<String> list = new ArrayList<>();list.add("张三");//0list.add("李四");//1list.add("王五");//2list.add("郭七");//3System.out.println(list);//void add(int index,E e) 在此集合中的指定位置插入指定的元素list.add(2, "赵六");System.out.println(list);
​//E remove(int index) 删除指定索引处的元素,返回被删除的元素 (一般不接收)list.remove(3);System.out.println(list);//E set(int index,E e) 修改指定索引处的元素,返回被修改的元素(一般不接收)list.set(1,"钱八");System.out.println(list);//E get(int index) 返回指定索引处的元素list.get(1);System.out.println(list.get(1));
​System.out.println(list);}
}

2.2 list集合遍历

List支持的遍历方式1. 迭代器2. 增强for循环3. Lambda表达式4. for循环(因为List集合有索引)
public class Demo2 {public static void main(String[] args) {List<String> list = new ArrayList<>();list.add("张三");list.add("李四");list.add("王五");list.add("王五");
​//1. 迭代器Iterator<String> iterator = list.iterator();while(iterator.hasNext()){String s = iterator.next();System.out.println(s);}System.out.println("===========================");
​//2. 增强for循环for (String s : list) {System.out.println(s);}System.out.println("===========================");
​//3. Lambda表达式list.forEach(e ->{System.out.println(e);});System.out.println("===========================");
​//4. for循环(因为List集合有索引)for (int i = 0; i < list.size(); i++) {String s = list.get(i);System.out.println(s);}
​
​}
}

2.3 ArrayList

2.3.1 ArrayList底层原理

ArrayList底层数据结构:基于数组实现特点:(查询快,增删慢)1. 查询速度快(通过索引直接定位)2. 增删效率低(增删的时候,需要移动增删元素后面的元素, 有时还需要进行扩容)适用场景:1. ArrayList适合于根据索引查询数据, 或者数据量不大的场景2. ArrayList不适合于数据量大, 同时又要频繁进行增删操作的场景底层原理:1. 利用无参构造器创建的集合,会在底层创建一个默认长度为0的数组ArrayList<String> list = new ArrayList();2. 添加第一个元素时,底层会创建一个新的长度为10的数组list.add("a");3. 存满时,会扩容1.5倍比如存入第11个元素的时候, 长度会扩容到154. 如果一次添加多个元素, 1.5倍还放不下, 则新创建数组的长度以实际为准比如原来是10个元素,现在又要存入10个, 则长度会扩容到20

2.3.2 LinkedList集合的底层原理

LinkedList底层数据结构:基于双向链表实现(内存地址不连续,每个元素记录自己的前后元素)特点:1. 查询速度慢2. 增删效率高3. 对于首尾元素进行增删改查的速度都是极快的应用场景:1. 用来设计队列(两端开口,类似于一个管道,先进先出)只操作首尾元素, 尾部添加, 首部删除2. 用来设计(一段开口,类似于弹夹,先进后出)

 

public class Demo4 {
​public static void main(String[] args) {makeQueue();System.out.println("----------------");makeStack();}
​/*队列: 两端开口,特点是先进先出(排队)从队列后端入队列:  addLast 方法从队列前端出队列:  removeFirst方法*/public static void makeQueue() {
​LinkedList<String> queue = new LinkedList<>();
​//从队列后端入队列: addLast方法queue.addLast("第1位顾客");queue.addLast("第2位顾客");queue.addLast("第3位顾客");queue.addLast("第4位顾客");System.out.println(queue);
​//从队列前端出队列: removeFirst方法System.out.println(queue.removeFirst());System.out.println(queue.removeFirst());System.out.println(queue);}
运行结果:[第1位顾客, 第2位顾客, 第3位顾客, 第4位顾客]第1位顾客第2位顾客[第3位顾客, 第4位顾客]
​/*栈: 顶端开口的结构,特点是先进后出进栈/压栈: push方法(底层封装了addFirst 方法)出栈/弹栈: pop方法底 (底层封装了removeFirst方法)*/public static void makeStack() {LinkedList<String> stack = new LinkedList<>();
​//进栈/压栈: push方法(底层封装了addFirst 方法)stack.push("第1颗子弹");stack.push("第2颗子弹");stack.push("第3颗子弹");stack.push("第4颗子弹");System.out.println(stack);
​//出栈/弹栈: pop方法底(底层封装了removeFirst方法)System.out.println(stack.pop());System.out.println(stack.pop());System.out.println(stack);}运行结果:[第4颗子弹, 第3颗子弹, 第2颗子弹, 第1颗子弹]第4颗子弹第3颗子弹[第2颗子弹, 第1颗子弹]   
}

三、Set系列集合

1、Set系列集合的特点是啥?

无序、不重复

2、Set集合的常见实现类有哪几个?各自有啥特点?

HashSet :无序、不重复

LinkedHashSet: 有序、不重复

TreeSet :可排序、不重复

public class Demo1 {public static void main(String[] args) {testHashSet();System.out.println("==========");testLinkedHashSet();System.out.println("==========");testTreeSet();}
​//HashSet: 无序、没有索引、不可重复private static void testHashSet() {HashSet<Integer> hashSet = new HashSet<>();hashSet.add(44);hashSet.add(33);hashSet.add(11);hashSet.add(22);hashSet.add(22);System.out.println(hashSet);}
​//LinkedHashSet: 存取有序、没有索引、不可重复private static void testLinkedHashSet() {LinkedHashSet<Integer> linkedHashSet = new LinkedHashSet<>();linkedHashSet.add(44);linkedHashSet.add(33);linkedHashSet.add(11);linkedHashSet.add(22);linkedHashSet.add(22);System.out.println(linkedHashSet);}
​//TressSet: 排序、无序、没有索引、不可重复private static void testTreeSet() {TreeSet<Integer> treeSet = new TreeSet<>();treeSet.add(44);treeSet.add(33);treeSet.add(11);treeSet.add(22);treeSet.add(22);System.out.println(treeSet);}
}
​

 

3.1 HashSet

3.1.1 哈希值

哈希值就是一int值,Java每个对象都可以通过hashCode方法,获取自己的哈希值public int hashCode():返回对象的哈希码值。 
​
​
哈希值特点1.同一个对象多次调用hashCode方法,返回的哈希值是相同的;2.不同的对象,他们哈希值大几率不相同,但是也有可能会相同(哈希碰撞)3.Object的hashCode方法根据"对象地址值"计算哈希值,子类重写后的hashCode方法可以根据"对象属性值"计算哈希值
​
使用场景HashSet集合判定两个对象的标准就是两个对象的hash值是否一致, 因此我们经常重写hashcode实现集合中对象去重
public class Demo2 {public static void main(String[] args) {//创建一个学生对象,获取对象的哈希值//1.同一个对象多次调用hashCode方法,返回的哈希值是相同的;Student student = new Student("Tom", 15);int code = student.hashCode();System.out.println(code);int code1 = student.hashCode();System.out.println(code1);
​//2.不同的对象,他们哈希值大几率不相同,但是也有可能会相同(哈希碰撞)Student student1 = new Student("Jerry", 16);int code2 = student1.hashCode();System.out.println(code2);//3.Object的hashCode方法根据"对象地址值"计算哈希值//子类重写后的hashCode方法可以根据"对象属性值"计算哈希值Student student2 = new Student("Jerry", 16);int code3 = student2.hashCode();System.out.println(code3);}
}
​
class Student{private String name;private int age;
​public Student() {}
​public Student(String name, int age) {this.name = name;this.age = age;}
​public String getName() {return name;}
​public void setName(String name) {this.name = name;}
​public int getAge() {return age;}
​public void setAge(int age) {this.age = age;}
​@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
​//重写hashCode方法,根据对象的属性值计算哈希值
​@Overridepublic int hashCode() {return Objects.hash(name, age);}
}

 

3.1.2 Set集合去重

需求:

创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合,要求:学生对象的成员变量值相同,我们就认为是同一个对象

分析

①定义学生类,创建HashSet集合对象, 创建学生对象

②把学生添加到集合

③在学生类中重写两个方法,hashCode()和equals(),自动生成即可

public class Demo2 {public static void main(String[] args) {//通过HashSet集合,存储学生数据(去重:需要重写hashCode()和equals())HashSet<Student> students = new HashSet<>();//构造几个学生对象,存入set集合Student student1 = new Student("Tom", 15);Student student2 = new Student("Tom", 15);Student student3 = new Student("Tim", 19);students.add(student1);students.add(student2);students.add(student3);System.out.println(students);}
}
​
class Student{private String name;private int age;
​public Student() {}
​public Student(String name, int age) {this.name = name;this.age = age;}
​public String getName() {return name;}
​public void setName(String name) {this.name = name;}
​public int getAge() {return age;}
​public void setAge(int age) {this.age = age;}
​@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
​//重写hashCode方法,根据对象的属性值计算哈希值
​@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Student student = (Student) o;return age == student.age && Objects.equals(name, student.name);}
​@Overridepublic int hashCode() {return Objects.hash(name, age);}
}

 

3.1.3 HashSet集合的底层原理

  • 基于哈希表实现

  • 哈希表是一种增删改查数据,性能都较好的数据结构。

1、HashSet集合的底层原理是什么样的?

基于哈希表实现的。

JDK8之前的,哈希表:底层使用数组+链表组成

JDK8开始后,哈希表:底层采用数组+链表+红黑树组成。

2、HashSet集合利用哈希表操作数据的详细流程是咋回事?

① 创建一个默认长度16,默认加载因为0.75的数组,数组名table

② 根据元素的哈希值跟数组的长度计算出应存入的位置

③ 判断当前位置是否为null,如果是null直接存入,如果位置不为null,表示有元素,

则调用equals方法比较属性值,如果一样,则不存,如果不一样,则存入数组.

④ 当数组存满到16*0.75=12时,就自动扩容,每次扩容原先的1倍

 

 

3.2 LinkedHashSet

3.3 TreeSet

TreeSet 可排序(默认升序排序 ,按照元素的大小,由小到大排序)、不重复无索引底层基于红黑树实现排序,排序规则认为属性是相同的对象则不存
​
TreeSet的排序对于数值型Integer、Double,默认按照数值升序排列;对于String类型数据,默认按照字典排序对于自定义类,默认是无法排序的,需要我们指定排序规则1.自然排序:自定义类实现Comparable接口,重写compareTo方法,指定排序规则2.比较器排序:写在TreeSet构造参数中传递Comparator比较器对象,重写compare方法,指定排序规则
​
​

需求 使用TreeSet存储教师对象,重复对象不存,并且用两种方式按照年龄升序排列

//比较器排序:写在TreeSet构造参数中传递Comparator比较器对象,重写compare方法,指定排序规则
public class Demo4 {
​public static void main(String[] args) {//创建TreeSetTreeSet<Teacher> treeSet = new TreeSet<>(new Comparator<Teacher>() {@Overridepublic int compare(Teacher o1, Teacher o2) {return o1.getAge()-o2.getAge();}});
​//添加学生treeSet.add(new Teacher("张三", 19));treeSet.add(new Teacher("李四", 18));treeSet.add(new Teacher("王五", 20));treeSet.add(new Teacher("赵六", 17));treeSet.add(new Teacher("赵六", 17));
​//打印for (Teacher teacher : treeSet) {System.out.println(teacher);}}
}
​
class Teacher {private String name;private int age;
​public Teacher() {}
​public Teacher(String name, int age) {this.name = name;this.age = age;}
​public String getName() {return name;}
​public void setName(String name) {this.name = name;}
​public int getAge() {return age;}
​public void setAge(int age) {this.age = age;}
​@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +'}';}
​
}
运行结果:Teacher{name='赵六', age=17}Teacher{name='李四', age=18}Teacher{name='张三', age=19}Teacher{name='王五', age=20}
//自然排序:自定义类实现Comparable接口,重写compareTo方法,指定排序规则
public class Demo5 {public static void main(String[] args) {//创建TreeSetTreeSet<Teacher1> treeSet = new TreeSet<>();//添加学生treeSet.add(new Teacher1("张三", 19));treeSet.add(new Teacher1("李四", 18));treeSet.add(new Teacher1("王五", 20));treeSet.add(new Teacher1("赵六", 17));treeSet.add(new Teacher1("赵六", 17));//打印for (Teacher1 teacher : treeSet) {System.out.println(teacher);}}
}class Teacher1 implements Comparable<Teacher1>{private String name;private int age;public Teacher1() {}public Teacher1(String name, int age) {this.name = name;this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", age=" + age +'}';}@Overridepublic int compareTo(Teacher1 o) {return this.age - o.age;}
}
运行结果:Teacher{name='赵六', age=17}Teacher{name='李四', age=18}Teacher{name='张三', age=19}Teacher{name='王五', age=20}

四、总结


http://www.mrgr.cn/news/18525.html

相关文章:

  • TFT液晶面板中应用的高度集成的电源管理芯片(PMIC)-iML1942
  • 道可云人工智能元宇宙每日资讯|《扬州市数字人才引育用留十条举措》发布
  • 构建Spring Boot应用的微服务服务契约管理
  • Excel vloopup应用案例
  • 金融风控科研论文必须要了解的15个学术网站
  • python 实现perfect cube完全立方数算法
  • 使用Spring Boot集成Redis缓存
  • 问:说说Java中泛型,怎么用?
  • 百万豪车同款!上半年交付暴涨5倍,AR HUD强攻20万以下车型
  • MySQL——事务与存储过程(三)存储过程的使用(2) 查看存储过程
  • 华为OD机试真题 - 石头剪刀布游戏(Python/JS/C/C++ 2024 D卷 100分)
  • 面向对象八股文(长期跟新_整理收集_排版未优化_day03_20个)
  • Kafka:浅谈对Kafka的认识
  • 基于STM32的智能冷链监控系统:MQTT协议与GPS模块设计(代码示例)
  • Android Audio分区——音频分区相关API(四)
  • java基础知识-JVM知识详解
  • 下载xhsell连接Linux系统
  • 鸿蒙之华为登录页
  • 十七、网络编程
  • 0901作业+思维导图梳理