Collection集合

  • 集合概述
  • 集合的体系特点
  • Collection集合常用API
  • Collection集合的遍历方式
    • 方式一:迭代器
    • 方式二:foreach/增强for循环
    • 方式三:lambda表达式
  • Collection集合存储自定义类型的对象
  • List系列集合
    • List集合特点、特有API
    • List集合的遍历方式小结
    • ArrayList集合的底层原理
    • LinkedList集合的底层原理
  • Set系列集合
    • Set系列集系概述
    • HashSet元素无序的底层原理:哈希表
    • HashSet元素去重复的底层原理
    • 实现类:LinkedHashSet
    • 实现类:TreeSet

集合概述

集合和数组都是容器。
数组特点:

1、 数组定义完成并启动后,类型确定、长度固定。2、适合元素的个数和类型确定的业务场景,不适合做需要增删数据操作。

集合特点:

1、集合的大小不固定,启动后可以动态变化,类型也可以选择不固定。集合更像气球。
2、集合非常适合做元素的增删操作。

问题1、数组和集合的元素存储的个数问题。

数组定义后类型确定,长度固定
集合类型可以不固定,大小是可变的。

问题2、数组和集合存储元素的类型问题。

数组可以存储基本类型和引用类型的数据。
集合只能存储   引用数据类型    的数据。

问题3、数组和集合适合的场景

数组适合做数据个数和类型确定的场景。
集合适合做数据个数不确定,且要做增删元素的场景。

集合的体系特点

集合类 体系结构
Collection单列集合,每个元素(数据)只包含一个值,Map双列集合,每个元素包含两个值(键值对)

Collection集合体系
Collection集合特点
List系列集合: 添加的元素是 有序、 可重复、 有索引。

ArrayList、LinekdList :有序、可重复、有索引。

Set系列集合: 添加的元素是无序、不重复、无索引。

HashSet: 无序、不重复、无索引;LinkedHashSet: 有序、不重复、无索引。
TreeSet:按照大小默认升序排序、不重复、无索引。

集合对于泛型的支持

集合都是支持泛型的,可以在编译阶段约束集合只能操作某种数据类型
Collection<String> lists = new ArrayList<String>();
Collection<String> lists = new ArrayList<>(); // JDK 1.7开始后面的泛型类型申明可以省略不写注意:集合和泛型都只能支持引用数据类型,不支持基本数据类型,所以集合中存储的元素都认为是对象。
Collection<int> lists = new ArrayList<>();  // 这种写法是错误的,int为基本数据类型如果集合中要存储基本类型的数据怎么办?
// 存储基本类型使用包装类
Collection<Integer> lists = new ArrayList<>();
Collection<Double> lists = new ArrayList<>();

问题1、集合的代表是?

Collection接口。

问题2、Collection集合分了哪2大常用的集合体系?

List系列集合:添加的元素是有序、可重复、有索引。
Set系列集合:添加的元素是无序、不重复、无索引。

问题3、如何约定集合存储数据的类型,需要注意什么?

集合支持泛型。
集合和泛型不支持基本类型,只支持引用数据类型。

测试代码:

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;public class CollectionTest {public static void main(String[] args) {// List接口(实现类:ArrayList && LinkList)// 有序,可重复 --- > 有索引Collection list = new ArrayList();  // 多态的写法list.add("java");list.add("java");list.add("Mybatis");list.add(23);list.add(23);list.add(false);list.add(false);System.out.println(list.toArray());System.out.println(list);System.out.println(list.toString());// set接口(实现类HashSet,TreeSet) 无序 不重复 -- > 无索引Collection list1 = new HashSet();list1.add("java");list1.add("java");list1.add("Mybatis");list1.add(23);list1.add(23);list1.add(false);list1.add(false);System.out.println(list1);System.out.println(list1.toString());System.out.println("--------------------------------");// 集合和泛型都不支持基本数据类型Collection<String> list3 = new ArrayList<>();  // <包裹的为泛型>表示只能存储该引用类型的数据,其它类型不能进行存储list3.add("Java");list3.add("1234");
//        list3.add(1);System.out.println(list3);Collection<Integer> list2 = new ArrayList<>();list2.add(34);  // 自动装箱处理 int  -- > Integerlist2.add(new Integer(23)); // 有参构造list2.add(34);System.out.println(list2);}
}

Collection集合常用API

Collection集合 :Collection是 单列集合 的 祖宗接口,它的功能是全部单列集合都可以继承使用的。
Collection API如下:

方法名称 说明
public boolean add(E e) 把给定的对象添加到当前集合中
public void clear() 清空集合中的所有元素
public boolean remove(E e) 把给定的对象在当前集合中删除
public boolean contains(Object obj) 判断当前集合中是否包含给定的对象
public boolean isEmpty() 判断当前集合是否为空
public int size() 返回集合中的元素个数
public Object[] toArray() 把集合中的元素存储到数组中
测试代码:
public class CollectionDemo {public static void main(String[] args) {Collection<String> collection = new ArrayList<>();// 1. 添加元素collection.add("Java");collection.add("HTML");collection.add("Mysql");collection.add("黑马");collection.add("Java");collection.add("Mysql");System.out.println(collection);  // 直接打印实例化对象的名称,会默认调用toString方法,如果打印的为地址的话说明没有重写toStringSystem.out.println(collection.toString());// 2. 清空元素集合
//        collection.clear();
//        System.out.println(collection);// 3. 判断集合是否为空,是空返回true, 反之返回falseSystem.out.println(collection.isEmpty());// 4. 获得集合大小System.out.println(collection.size());// 5. 判断集合中是否包含某个元素System.out.println(collection.contains("java"));  // falseSystem.out.println(collection.contains("Java"));  // trueSystem.out.println(collection.contains("黑马"));  // true// 6. 删除某个元素:如果有多个重复元素,默认删除第一个System.out.println(collection.remove("Java")); // tureSystem.out.println(collection);System.out.println(collection.remove("lushimeng"));  // falseSystem.out.println(collection);// 7. 把集合转换成数组// 集合转换为数组只能是Object类型,原因在于防止数组集合中有其他类型的数据// 虽然通过<类型>进行了限制,但是可以绕过限制把其他类型的数据加入到集合中,// 所以为了安全起见都转化为Object类型的数组Object[] array = collection.toArray();System.out.println(Arrays.toString(array));// 8. 把一个集合加到另一个集合后面Collection<Integer> collection1 = new ArrayList<>();collection1.add(10);collection1.add(20);collection1.add(30);System.out.println(collection1);Collection<Integer> collection2 = new ArrayList<>();collection2.add(40);collection2.add(50);System.out.println(collection2);// addAll把collection2集合中的元素全部加入到collection中collection1.addAll(collection2);System.out.println(collection1);System.out.println(collection2);}
}

Collection集合的遍历方式

方式一:迭代器

迭代器遍历概述:遍历就是一个一个的把容器中的元素访问一遍。 迭代器在Java中的代表是Iterator,迭代器是集合的专用遍历方式。
Collection集合获取迭代器

方法名称 说明
Iterator<E> iterator() 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的0索引
Iterator中的常用方法
方法名称 说明
boolean hasNext() 询问当前位置是否有元素存在,存在返回true,不存在返回false
E next 获取当前位置的元素,并同时将迭代器对象移向下一个位置,注意防止取出边界
迭代器测试案例:
public class CollectionDemo01 {public static void main(String[] args) {Collection<Integer> collection = new ArrayList<>();collection.add(100);collection.add(200);collection.add(300);collection.add(400);System.out.println(collection);// 1. 得到当前集合的迭代器对象Iterator<Integer> it = collection.iterator();  // iterator静态方法,返回一个Iterator<Integer>对象while (it.hasNext()){int number = it.next();System.out.println(number);}}
}

问题1、迭代器的默认位置在哪里。

Iterator<E> iterator():得到迭代器对象,默认指向当前集合的索引0

问题2、迭代器如果取元素越界会出现什么问题。

会出现NoSuchElementException异常。

方式二:foreach/增强for循环

增强for循环格式:

for(元素数据类型 变量名 : 数组或者Collection集合) {//在此处使用变量即可,该变量就是元素
}

增强for循环:既可以遍历集合也可以遍历数组。
增强for循环/foreach测试案例:

public class CollectionDemo02 {public static void main(String[] args) {Collection<String> lists = new ArrayList<>();lists.add("赵敏");lists.add("校招");lists.add("潘晓");lists.add("王亮");System.out.println(lists);// foreach/增强for循环for(String str : lists){System.out.println(str);}System.out.println("-----------------------");double[] scores = {100, 98.5, 59.5};for (double score : scores) {System.out.println(score);}System.out.println(Arrays.toString(scores));}
}

问题1、增强for可以遍历哪些容器?

既可以遍历集合也可以遍历数组。

问题2、增强for的关键是记住它的遍历格式

for(元素数据类型 变量名 : 数组或者Collection集合) {//在此处使用变量即可,该变量就是元素
}

方式三:lambda表达式

Lambda表达式遍历集合:得益于JDK 8开始的新技术Lambda表达式,提供了一种更简单、更直接的遍历集合的方式。
Collection结合Lambda遍历的API

方法名称 说明
default void forEach(Consumer<? super T> action): 结合lambda遍历结合
lambda遍历结合案例:
import java.util.ArrayList;
import java.util.Collection;
import java.util.function.Consumer;public class CollectionDemo03 {public static void main(String[] args) {Collection<String> lists = new ArrayList<>();lists.add("赵敏");lists.add("校招");lists.add("潘晓");lists.add("王亮");System.out.println(lists);//        lists.forEach(new Consumer<String>() {//            @Override
//            public void accept(String s) {//                System.out.println(s);
//            }
//        });//        // lambda应用
//        lists.forEach((String s) -> {//            System.out.println(s);
//        });// lambda应用
//        lists.forEach( s -> System.out.println(s)
//        );lists.forEach(System.out::println);}
}

Collection集合存储自定义类型的对象

需求

某影院系统需要在后台存储上述三部电影,然后依次展示出来。
分析
1:定义一个电影类,定义一个集合存储电影对象。
2:创建3个电影对象,封装相关数据,把3个对象存入到集合中去。
3:遍历集合中的3个对象,输出相关信息。

案例实现 Movie类:

public class Movie {private String name;private double score;private String actor;public Movie(){}public Movie(String name, double score, String actor){this.name = name;this.score = score;this.actor = actor;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getScore() {return score;}public void setScore(double score) {this.score = score;}public String getActor() {return actor;}public void setActor(String actor) {this.actor = actor;}@Overridepublic String toString() {  // 返回值类型为String类型, 在Movie类中重写toString,要不然会打印地址而不是内容return "Movie{" +"name='" + name + '\'' +", score=" + score +", actor='" + actor + '\'' +'}';}
}

案例实现 Test测试类:

import java.util.*;
import java.util.function.Consumer;public class TestDemo {public static void main(String[] args) {Collection<Movie> movieCollection = new ArrayList<>();movieCollection.add(new Movie("《你好, 李焕英》", 9.5 , "贾玲"));movieCollection.add(new Movie("《唐人街探案》", 8.5, "王宝强"));movieCollection.add(new Movie("《刺杀小说家》", 8.6 , "雷佳音"));System.out.println(movieCollection);  // 默认调用toString方法,// 1. 迭代器访问集合Iterator<Movie> it = movieCollection.iterator();while (it.hasNext()){Movie movie = it.next();System.out.println(movie.toString());}System.out.println("--------------------------------------------");// 2. foreach/增强for循环访问集合for(Movie movie : movieCollection){System.out.println("电影名称:" + movie.getName() + ", 评分:" + movie.getScore() + ", 演员:" + movie.getActor());}System.out.println("--------------------------------------------");// 3. lambda访问集合
//        movieCollection.forEach(new Consumer<Movie>() {//            @Override
//            public void accept(Movie movie) {//                System.out.println("电影名称:" + movie.getName() +
//                        ", 评分:" + movie.getScore() +
//                        ", 演员:" + movie.getActor());
//
//            }
//        });//        movieCollection.forEach((Movie movie) -> {//            System.out.println("电影名称:" + movie.getName() +
//                    ", 评分:" + movie.getScore() +
//                    ", 演员:" + movie.getActor());
//
//        });//        movieCollection.forEach(movie -> System.out.println("电影名称:" + movie.getName() + ", 评分:" + movie.getScore() + ", 演员:" + movie.getActor()));//        movieCollection.forEach(System.out::println);  // Movie类中要重写toString方法,要不然输出的为地址}
}

List系列集合

List集合特点、特有API

List系列集合特点:ArrayList、LinekdList :有序,可重复,有索引。

有序:存储和取出的元素顺序一致
有索引:可以通过索引操作元素
可重复:存储的元素可以重复

List集合特有方法:List集合因为支持索引,所以多了很多索引操作的独特api,其他Collection的功能List也都继承了。
方法测试案例:

public class ListDemo01 {public static void main(String[] args) {// 1. 创建一个ArrayList集合对象// List: 有序,可重复,有索引List<String> list = new ArrayList<>();list.add("Java");list.add("Java");list.add("HTML");list.add("HTML");list.add("Mysql");list.add("Mysql");System.out.println(list);// 2. 在某个索引位置插入元素list.add(2, "黑马");System.out.println(list);// 3. 根据索引删除元素,返回被删除元素System.out.println(list.remove(1));System.out.println(list);// foreach / 增强for循环for(String str : list){System.out.println(str);}// 5. 修改索引位置处的元素System.out.println(list.set(1, "lushimeng"));System.out.println(list);}
}

问题1、List系列集合特点

  ArrayList、LinekdList :有序,可重复,有索引。

问题2、List的实现类的底层原理

ArrayList底层是   基于数组     实现的,根据查询元素快,增删相对慢。
LinkedList底层   基于双链表    实现的,查询元素慢,增删首尾元素是非常快的。

List集合的遍历方式小结

List集合的遍历方式有几种?
1、迭代器 ;
2、增强for循环;
3、Lambda表达式;
4、for循环(因为List集合存在索引)
测试案例:

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class ListDemo02 {public static void main(String[] args) {// 1. 创建一个ArrayList集合对象// List: 有序,可重复,有索引List<String> list = new ArrayList<>();list.add("Java");list.add("Java");list.add("HTML");list.add("HTML");list.add("Mysql");list.add("Mysql");System.out.println(list);// 4. 根据索引获取元素// 4.1 for循环遍历方式for(int i = 0; i < list.size(); i++){System.out.println(list.get(i));}System.out.println("------------------------------");// 4.2 迭代器iterator遍历方式Iterator<String> it = list.iterator();while (it.hasNext()){String str = it.next();System.out.println(str);}System.out.println("------------------------------");// 4.3 foreach / 增强for循环for(String str : list){System.out.println(str);}System.out.println("------------------------------");// 4.4 JDK1.8之后开始有lambda表达式list.forEach(s -> System.out.println(s));System.out.println("------------------------------");list.forEach(System.out::println);}
}

ArrayList集合的底层原理

ArrayList集合底层原理
ArrayList底层是基于数组实现的:根据索引定位元素快,增删需要做元素的移位操作。 第一次创建集合并添加第一个元素的时候,在底层创建一个默认长度为10的数组

LinkedList集合的底层原理

LinkedList的特点:底层数据结构是双链表,查询慢,首尾操作的速度是极快的,所以多了很多首尾操作的特有API,可以用其做入栈,出栈,队列等操作

LinkedList集合的特有功能:
测试案例:

public class ListDemo03 {public static void main(String[] args) {// LinkedList可以完成队列结构和栈结构(双链接)// 1. 做一个队列LinkedList<String> queue = new LinkedList<>();// 1. 入队queue.addLast("1");queue.addLast("2");queue.addLast("3");queue.addLast("4");queue.addLast("5");System.out.println(queue);  // [1, 2, 3, 4, 5]// 出队System.out.println(queue.getFirst());System.out.println(queue.removeFirst());System.out.println(queue);  // [2, 3, 4, 5]// 1. 做一个栈LinkedList<String> stack = new LinkedList<>();// 入栈stack.push("第1颗子弹");stack.push("第2颗子弹");stack.push("第3颗子弹");stack.push("第4颗子弹");System.out.println(stack);  // [第4颗子弹, 第3颗子弹, 第2颗子弹, 第1颗子弹]// 出栈System.out.println(stack.removeFirst());  // 第4颗子弹System.out.println(stack.pop());  // 第3颗子弹System.out.println(stack);  // [第2颗子弹, 第1颗子弹]System.out.println("------------------------------------");LinkedList<Integer> linkedList = new LinkedList<>();linkedList.addLast(1);linkedList.addLast(2);linkedList.addLast(3);linkedList.addLast(4);linkedList.addLast(5);linkedList.addLast(6);linkedList.addLast(7);for (int i = 0; i < linkedList.size(); i++) {System.out.print(linkedList.get(i) + "  ");}System.out.println();System.out.println("------------------------------------");// 迭代器Iterator<Integer> it = linkedList.iterator();while (it.hasNext()){System.out.println(it.next());}System.out.println("------------------------------------");// foreach/增强for循环for(Integer integer : linkedList){System.out.println(integer);}System.out.println("------------------------------------");// jdk 1.8之后lambda表达式遍历集合方式linkedList.forEach(s -> System.out.println(s));}
}

Set系列集合

Set系列集系概述

Set系列集合特点

1、无序:存取顺序不一致
2、不重复:可以去除重复
3、无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素。

Set集合实现类特点

1、HashSet : 无序、不重复、无索引。
2、LinkedHashSet:有序、不重复、无索引。
3、TreeSet:排序、不重复、无索引。

Set集合的功能上基本上与Collection的API一致。
测试代码:

public class SetDemo1 {public static void main(String[] args) {// Set系列集合的特点:HashSet LinkedHashSet  TreeSet
//        Set<String> set = new HashSet<>();  // 无序  不重复  无索引  [Java, A, Mysql, SpringBoot]
//        Set<String> set = new LinkedHashSet<>();  // 有序  不重复  无索引  [Java, Mysql, SpringBoot, A]Set<String> set = new TreeSet<>();  // 升序  不重复  无索引  [Java, Mysql, SpringBoot]set.add("Java");set.add("Java");set.add("Mysql");set.add("Mysql");set.add("SpringBoot");set.add("SpringBoot");set.add("A");System.out.println(set); // 默认调用toString方法,集合都重写了Object类中的toString方法}
}

HashSet元素无序的底层原理:哈希表

HashSet底层原理

HashSet集合底层采取   哈希表   存储的数据。
哈希表是一种对于增删改查数据性能都较好的结构。

哈希表的组成

JDK8之前的,底层使用   数组  +    链表   组成
JDK8开始后,底层采用   数组   +   链表   +   红黑树   组成。

哈希值:是JDK根据对象的地址,按照某种规则算出来的int类型的数值,Object类的API public int hashCode​():返回对象的哈希值

对象的哈希值特点

同一个对象多次调用hashCode()方法返回的哈希值是相同的
默认情况下,不同对象的哈希值是不同的。

HashSet1.7版本原理解析:数组 + 链表 +(结合哈希算法)

1、创建一个默认长度16的数组,数组名table
2、根据元素的哈希值跟数组的长度求余计算出应存入的位置(哈希算法)
3、判断当前位置是否为null,如果是null直接存入
4、如果位置不为null,表示有元素,则调用equals方法比较
5、如果一样,则不存,如果不一样,则存入数组JDK 7新元素占老元素位置,指向老元素JDK 8中新元素挂在老元素下面`

JDK1.8版本开始HashSet原理解析

底层结构:哈希表(数组、链表、红黑树的结合体)
当挂在元素下面的数据过多时,查询性能降低,从JDK8开始后,当链表长度超过8的时候,自动转换为红黑树。

问题1:Set集合的底层原理是什么样的?

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

问题2… 哈希表的详细流程

1、 创建一个默认长度16,默认加载因为0.75的数组,数组名table
2、 根据元素的哈希值跟数组的长度计算出应存入的位置
3、判断当前位置是否为null,如果是null直接存入,如果位置不为null,表示有元素,  则调用equals方法比较属性值,如果一样,则不存,如果不一样,则存入数组。
4、当数组存满到16*0.75=12时,就自动扩容,每次扩容原先的两倍

问题提出:你可以发现下图中new了两个字符串对象str1,str2两个字符的内容相同,按照上面对象的哈希值特点知:不同对象的哈希值是不同的。但是下面的实验结果却显示相同,这个要怎么理解呢?
问题解答:经过调研发现与equals和hashCode方法重写有关,我们知道任何类都继承Object类,Object类中有equals方法方法的作用是比较两个对象的地址是否一样。而我们在String类里面重写了equlas方法用来比较字符串内容是否一致
主要是Object.hashCode的通用约定:
a. 在java应用程序运行时,无论何时多次调用同一个对象时的hsahCode()方法,这个对象的hashCode()方法的返回值必须是相同的一个int值.
b. 如果两个对象equals()返回值为true,则他们的hashCode()也必须返回相同的int值.
c. 如果两个对象equals()返回值为false,则他们的hashCode()返回值也必须不同.

 String s1 = new String("1111");String s2 = new String("1111");s1.hashCode();s2.hashCode();System.out.println(s1.equals(s2));

s1和s2对象所指的内存地址是不一样的,一个对象的hashcode是内存地址进行hash运算而得,如果string没有重写hashcode,那么s1和s2的hashcode 也有可能是不一样的。如果用Obejct的equals方法,那么比较的手机两个对象在堆内存的地址,那么结果会是是false,但是在业务系统中我们需要的是对象属性是否一致,所以重写了equals方法。string的底层数据结构是char数组,所以重写equals的逻辑就是两个对象的char数组循环比较值。那么equals重写了,但是如果hashcode没有重写那就违反了Object.hashCode的通用约定,所以hashCode必须也重写。可以从源码看出,两个值相等的String 的hashCode一定相等。
参考连接:https://www.cnblogs.com/zhengyixin/p/14891400.html

HashSet元素去重复的底层原理

1、创建一个默认长度16的数组,数组名table
2、根据元素的哈希值跟数组的长度求余计算出应存入的位置(哈希算法)
3、判断当前位置是否为null,如果是null直接存入
4、如果位置不为null,表示有元素,则调用equals方法比较
4、如果一样,则不存,如果不一样,则存入数组,

结论:如果希望Set集合认为2个内容一样的对象是重复的,必须重写对象的hashCode()和equals()方法
案例需求:

创建一个存储学生对象的集合,存储多个学生对象,使用程序实现在控制台遍历该集合,要求:学生对象的成员变量值相同,我们就认为是同一个对象分析:
1、定义学生类,创建HashSet集合对象, 创建学生对象
2、把学生添加到集合
3、在学生类中重写两个方法,hashCode()和equals(),自动生成即可
4、遍历集合(增强for)

Student类:

import java.util.Objects;public class Student {private String name;private int age;private char sex;public Student() {}public Student(String name, int age, char sex) {this.name = name;this.age = age;this.sex = sex;}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;}public char getSex() {return sex;}public void setSex(char sex) {this.sex = sex;}/*** 重写equals方法,判断内容是否想等* @param o* @return*/@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 && sex == student.sex && Objects.equals(name, student.name);}/*** 重写hashCode方法,把相容内容的对象只存储一个。* @return*/@Overridepublic int hashCode() {return Objects.hash(name, age, sex);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", sex=" + sex +'}';}
}

StudentTest测试类:

/*** 在自定义类进行比较的时候,如果不设定比较规则会报错:ClassCastException*/
public class StudentTest {public static void main(String[] args) {// 方法二:集合自定义Comparator比较器对象,重写比较规则。// Comparator前面有@FunctionalInterface,可以使用lambda负责
//        Set<Student> set = new TreeSet<>(new Comparator<Student>() {//            @Override
//            public int compare(Student o1, Student o2) {//                return Double.compare(o1.getSum(), o2.getSum());  // 升序
                return Double.compare(o2.getSum(), o1.getSum()); // 降序
//            }
//        });
//        Set<Student> set = new TreeSet<>( (o1,o2) -> Double.compare(o1.getSum(), o2.getSum()));  // 升序Set<Student> set = new TreeSet<>( (o1,o2) -> Double.compare(o2.getSum(), o1.getSum()));  // 降序set.add(new Student("卢一", 100, 100, 100));set.add(new Student("赵二", 99, 93, 34));set.add(new Student("王三", 99, 99, 99));set.add(new Student("宋四", 87, 78, 78));System.out.println(set.toString());Student student1 = null; // 接收变量// 迭代器访问集合Iterator<Student> it = set.iterator(); // 获取迭代器对象while (it.hasNext()){  // 访问当前指针所指向的位置,是否有值student1 = it.next();  // 把内容取出来赋给student,然后指针向后移动一位System.out.println(student1.getName() + "\t" +student1.getChinese() + "\t" +student1.getMath() + "\t" +student1.getEnglish() + "\t" +student1.getSum());}System.out.println("--------------------------------------------------------");// 增强for循环访问集合for(Student stu : set){System.out.println(stu.getName() + "\t" +stu.getChinese() + "\t" +stu.getMath() + "\t" +stu.getEnglish() + "\t" +stu.getSum());}System.out.println("--------------------------------------------------------");// lambda访问集合set.forEach(student -> System.out.println(student.getName() + "\t" + student.getChinese() + "\t" +student.getMath() + "\t" +student.getEnglish() + "\t" +student.getSum()));}
}

代码截图:

实现类:LinkedHashSet

LinkedHashSet集合概述和特点

特点:有序(元素添加的顺序,而不是排序)、不重复、无索引。这里的有序指的是保证存储和取出的元素顺序一致
原理:底层数据结构是依然    哈希表,只是每个元素又额外的多了一个   双链表的机制    记录存储的顺序

实现类:TreeSet

TreeSet集合概述和特点

不重复、无索引、可排序
可排序:按照元素的大小    默认    升序(有小到大)   排序。
TreeSet集合底层是    基于红黑树    的数据结构实现排序的,增删改查性能都较好。
注意:TreeSet集合是一定要排序的,可以将元素按照指定的规则进行排序。

测试案例:

import java.util.*;
// 底层实现方式为链表 + 红黑树
public class SetDemo5 {public static void main(String[] args) {Set<Integer> sets = new TreeSet<>();  // 可排序 不重复 无索引sets.add(23);sets.add(12);sets.add(45);sets.add(9);System.out.println(sets);  // [9, 12, 23, 45]Set<String> set = new TreeSet<>();  // 有序 无重复  无索引set.add("Java");set.add("Java");set.add("angela");set.add("黑马");set.add("Java");set.add("About");set.add("UI");System.out.println(set);  // [About, Java, UI, angela, 黑马]

TreeSet集合默认的规则

对于数值类型:Integer , Double,官方默认按照大小进行   升序排序。
对于字符串类型:默认按照首字符的编号升序排序。
对于自定义类型如Student对象,TreeSet无法直接排序, 要使用自定义的排序规则。

结论:想要使用TreeSet存储自定义类型,需要制定排序规则
自定义排序规则:TreeSet集合存储对象的的时候有2种方式可以设计自定义比较规则

方式一: 让自定义的类(如学生类) 实现Comparable接口 重写 里面的 compareTo方法 来定制比较规则。
方式二:TreeSet集合有参数构造器,可以设置Comparator接口对应的比较器对象,来定制比较规则。

两种方式中,关于返回值的规则:

如果认为第一个元素大于第二个元素返回正整数即可。
如果认为第一个元素小于第二个元素返回负整数即可。
如果认为第一个元素等于第二个元素返回0即可,此时Treeset集合只会保留一个元素,认为两者重复。

注意:如果TreeSet集合存储的对象有实现比较规则,集合也自带比较器,默认使用集合自带的比较器排序。
TreeSet对象排序练习题

需求:键盘录入3个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台分析
1、定义学生类
2、创建TreeSet集合对象,通过比较器排序进行排序
3、创建学生对象
4、把学生对象添加到集合
5、遍历集合

Student类

public class Student implements Comparable<Student>{private String name;private double chinese;private double math;private double english;private double sum;public Student() {}public Student(String name, double chinese, double math, double english) {//        this.sum = chinese + math + english;this.name = name;this.chinese = chinese;this.math = math;this.english = english;// 必须放在chinese, math, english都已经赋值后的后面才可以,放在其前面,变量还没有被赋值,则sum计算结果为0this.SUM();}public void SUM(){this.sum = this.chinese + this.math + this.english;}public String getName() {return name;}public void setName(String name) {this.name = name;}public double getChinese() {return chinese;}public void setChinese(double chinese) {this.chinese = chinese;}public double getMath() {return math;}public void setMath(double math) {this.math = math;}public double getEnglish() {return english;}public void setEnglish(double english) {this.english = english;}public double getSum() {return sum;}public void setSum(double sum) {this.sum = sum;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", chinese=" + chinese +", math=" + math +", english=" + english +", sum=" + sum +'}';}/*** 类自定义比较规则,实现  Comparable接口   重写   里面的   compareTo方法    来定制比较规则* o2.compareTo(o1);* @param o* @return*/@Overridepublic int compareTo(Student o) {//        return this.sum >= o.sum ? 1 : -1;  // 按照升序排列return o.sum >= this.sum ? 1 : -1;  // 按照降序排列}
}

StudentTest类:

import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Consumer;/*** 在自定义类进行比较的时候,如果不设定比较规则会报错:ClassCastException*/public class StudentTest {public static void main(String[] args) {// 方法二:集合自定义Comparator比较器对象,重写比较规则。// Comparator前面有@FunctionalInterface,可以使用lambda负责
//        Set<Student> set = new TreeSet<>(new Comparator<Student>() {//            @Override
//            public int compare(Student o1, Student o2) {//                return Double.compare(o1.getSum(), o2.getSum());  // 升序
                return Double.compare(o2.getSum(), o1.getSum()); // 降序
//            }
//        });
//        Set<Student> set = new TreeSet<>( (o1,o2) -> Double.compare(o1.getSum(), o2.getSum()));  // 升序Set<Student> set = new TreeSet<>( (o1,o2) -> Double.compare(o2.getSum(), o1.getSum()));  // 降序set.add(new Student("卢一", 100, 100, 100));set.add(new Student("赵二", 99, 93, 34));set.add(new Student("王三", 99, 99, 99));set.add(new Student("宋四", 87, 78, 78));System.out.println(set.toString());Student student1 = null; // 接收变量// 迭代器访问集合Iterator<Student> it = set.iterator(); // 获取迭代器对象while (it.hasNext()){  // 访问当前指针所指向的位置,是否有值student1 = it.next();  // 把内容取出来赋给student,然后指针向后移动一位System.out.println(student1.getName() + "\t" +student1.getChinese() + "\t" +student1.getMath() + "\t" +student1.getEnglish() + "\t" +student1.getSum());}System.out.println("--------------------------------------------------------");// 增强for循环访问集合for(Student stu : set){System.out.println(stu.getName() + "\t" +stu.getChinese() + "\t" +stu.getMath() + "\t" +stu.getEnglish() + "\t" +stu.getSum());}System.out.println("--------------------------------------------------------");// lambda访问集合set.forEach(student -> System.out.println(student.getName() + "\t" + student.getChinese() + "\t" +student.getMath() + "\t" +student.getEnglish() + "\t" +student.getSum()));}
}

问题1:如果希望元素可以重复,又有索引,索引查询要快?
用ArrayList集合,基于数组的。(用的最多)
问题2: 如果希望元素可以重复,又有索引,增删首尾操作快?
用LinkedList集合,基于链表的。
问题3:如果希望增删改查都快,但是元素不重复、无序、无索引。
用HashSet集合,基于哈希表的。
问题4:如果希望增删改查都快,但是元素不重复、有序、无索引。
用LinkedHashSet集合,基于哈希表和双链表。
问题5:如果要对对象进行排序。
用TreeSet集合,基于红黑树。后续也可以用List集合实现排序。

Java中的Collection集合以及Collection集合实现类实例相关推荐

  1. java中list,set,map集合的区别,及面试要点

    Map集合:链接: Map集合的五种遍历方式及Treemap方法 Set集合:链接: Java中遍历Set集合的三种方法 TreeSet集合:链接: Java深入了解TreeSet,和迭代器遍历方法 ...

  2. Java中 方法引用、Stream流、及方法实例 D190401

    Java中 方法引用.Stream流.及方法实例 D190401 01.第三章:方法引用_什么是方法引用 1).什么是"方法引用":指引用现有的方法代替Lambda表达式--当我们 ...

  3. java中使用jxl导出excel表格的工具类(全网唯一亲测可用,在原来基础上扩展)

    java中后台导出excel的话,有两种方案,一是使用poi(不过由于是windows版本的,存在不兼容,但功能更多,更强大),而是使用jxl(纯java编写,不过兼容,简单一些),可以设置输出的ex ...

  4. Java中的数组,列表,集合,映射,元组,记录文字

    有时,当我对JavaScript的强大功能和表现力感到兴奋时,我发现自己错过了Java世界中的一两个功能. 除了lambda表达式/闭包或任何您想称为"匿名函数"的东西之外,它还对 ...

  5. JAVA中如何交换两个List集合的顺序呢?

    在JAVA中我们该如何交换两个List集合的顺序呢? /*** 交换两个集合的顺序* * @param a a集合* @param b b集合*/public static void swapList ...

  6. java中list元素排序_java list集合元素根据某些字段排序

    一.jdk1.6的环境下 新建ComparatorSort类,并实现Comparator接口,重写compare方法 降序排序:o1的元素>o2的元素,并返回-1:o1的元素小于o2的元素,并返 ...

  7. 六、Java中常用的API(通过包进行分类)————File类、IO流

    一.util工具包下的补充类 介绍io包之前,先补充介绍几个常用的工具类 1.Scanner类 什么是Scanner类 一个可以解析基本类型和字符串的简单文本扫描器. 例如,以下代码使用户能够从 Sy ...

  8. java中的switch用法,循环,方法,数组以及类

    选择结构语句之switch: switch语句在开发过程中的使用仅次于if语句的使用. switch语句: switch语句格式: switch(表达式) { case 值1: 语句体1; break ...

  9. Java中怎样将Json字符串转换成实体类

    场景 在Java中调用接口获取Json数据后,怎样转换成对应的实体类进行接受与存储. 实现 打开浏览器输入在线Json格式化,这里推荐使用: http://www.bejson.com/ 选择Json ...

  10. java中商业数据计算时用到的类BigDecimal和DecimalFormat

    1.引言 借用<Effactive Java>这本书中的话,float和double类型的主要设计目标是为了科学计算和工程计算.他们执行二进制浮点运算,这是为了在广域数值范围上提供较为精确 ...

最新文章

  1. spark mysql 驱动_spark读取mysql数据库的驱动问题
  2. python【蓝桥杯vip练习题库】ADV-236林丹大战李宗伟
  3. Classical Inheritance in JavaScript
  4. java 迪杰斯特拉_Java 实现Dikstra迪杰斯特拉算法 关于单源顶点最短路径问题的求解...
  5. Github、Jekyll 搭建及优化静态博客方法指南
  6. 单片机复位电路电容一定用电解电容_什么叫51单片机最小系统
  7. [导入]数据库物理模型设计的其他模式之继承模式
  8. php strpos与strrpos,PHP开发之 strpos stripos strrpos strripos的区别
  9. TextDetection文本检测数据集汇总
  10. R语言转换并保存json文件--使用jsonlite包
  11. 理想传输线终端短路开路和接纯电抗的沿线电压电流分布
  12. window安装python3后怎么用pyspark_pyspark:连接spark集群Windows环境搭建
  13. android recyclerview item自适应高度_web前端学习:高度自适应知识点
  14. Mac 自定义用户级别Applications, 安装应用到Dashboard
  15. h5 移动端电子签名
  16. IDEA:Windows 下载安装 IDEA 详细教程
  17. 计算机系统中引入多道程序设计的目的在于,引入多道程序的目的在于什么
  18. 程序员述职报告范文_程序员个人年度工作总结范文
  19. 2020年鼠年正月十二 淡然面对
  20. 这些独家记忆串成我们的2022

热门文章

  1. PHP之支付宝APP支付
  2. Kanban看板管理实践精要
  3. 西瓜书第三章习题及答案
  4. gazebo plugins
  5. git版本控制gitosis的安装与使用
  6. C++ 小游戏 视频及资料集(十)
  7. AntV G6 自定义节点图形
  8. 什么计算机网络成瘾,计算机网络与网络成瘾.pdf
  9. MySQL中更新时间字段的更新时点问题
  10. Eclipse+Java+Swing实现电子商城