十三、集合进阶——单列集合 及 数据结构
单列集合 及 数据结构
- 13.1 集合体系结构
- 13.1.2 单列集合
- 1. Collection
- 2.Collection 的遍历方式
- 迭代器遍历
- 增强for遍历
- Lambda表达式遍历
- 3.List集合
- List集合的特有方法
- List集合的遍历方式
- 五种遍历方式对比
- 4.数据结构
- 1).栈
- 2).队列
- 3)数组
- 4)链表
- 小结
- 5)树
- 6)二叉查找树
- 7)平衡二叉树
- 平衡二叉树旋转机制——左旋
- 平衡二叉树旋转机制——右旋
- 平衡二叉树需要旋转的四种情况
- 8)红黑树
- 添加节点的规则
- 5.ArrayList集合
- 1.ArrayList集合底层原理
- 2.LinkedList集合
- 3.迭代器底层源码解析
- 6.泛型深入
- 1)泛型概述
- 2)泛型类
- 3)泛型方法
- 4)泛型接口
- 5)泛型的继承和通配符
- 总结
- 7.Set系列集合
- 1)HashSet
- 2)LinkedHashSet
- 3)TreeSet
- 8.单列集合使用场景
13.1 集合体系结构
13.1.2 单列集合
- List系列集合:添加的元素是有序、可重复、有索引。
- Set系列集合:添加的元素是无序、不重复、无索引。
1. Collection
Collection 是单列集合的祖宗接口,它的功能是全部单列集合都可以继承使用的。
public static void main(String[] args) {/*注意点:* Collection 是一个接口,我们不能直接创建他的对象。* 所以,在学习它的方法时,只能创建他实现类的对象* 实现类:ArrayList** 目的:为了学习Collection接口里面的方法。*/Collection<String> coll = new ArrayList<>();//0.添加元素System.out.println("-------------0.添加元素-------------");/*细节1:如果要往List系列集合中添加数据,那么方法永远返回true,因为List系列的是允许元素重复的。* 细节2:如果要往Set系列集合中添加数据,如果当前要添加元素不存在,方法返回true,表示添加成功。* 如果当前要添加的元素已经存在,方法返回false,表示添加失败* 因为Set系列的集合不允许重复。*/coll.add("zhangsan");coll.add("aaa");coll.add("bbb");coll.add("ccc");System.out.println(coll); // [zhangsan, aaa, bbb, ccc]//1.清空System.out.println("-------------1.清空-------------");
// coll.clear();System.out.println(coll); // []//2.删除//细节1:因为Collection里面定义的是共性的方法,所以此时不能通过索引删除,只能通过元素的对象进行删除。//细节2:方法会有一个返回值,删除成功返回true,删除失败返回false。System.out.println("-------------2.删除-------------");coll.remove("aaa");System.out.println(coll); // [zhangsan, bbb, ccc]//3.判断元素是否包含/*细节:底层是依赖equals方法进行判断是否存在的。* 所以,如果集合中存储的是自定义对象,也想通过contains方法来判断是否包含,那么在javabean类中,一定要重写equals方法*/System.out.println("-------------3.判断元素是否包含-------------");System.out.println(coll.contains("aaa")); //falseSystem.out.println(coll.contains("bbb")); // trueSystem.out.println("------------------------------------------");//4.判断是否为空System.out.println("-------------3.判断元素是否包含-------------");System.out.println(coll.isEmpty()); //falseSystem.out.println("------------------------------------------");//5.获取集合的长度int size = coll.size();System.out.println(size); // 3}
Contains方法 细节:
public static void main(String[] args) {//0.创建集合对象Collection<Student> coll = new ArrayList<>();//1.创建三个学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 25);Student s3 = new Student("wangwu", 26);//2.把学生对象添加到集合中coll.add(s1);coll.add(s2);coll.add(s3);//3.判断集合中某一个学生对象是否包含Student s4 = new Student("zhangsan", 23);/*因为contains方法在底层依赖equals方法判断对象是否一致的。如果存的是自定义对象,没有重写equals方法,那么默认使用Object类中的equals方法进行判断,而Object类中equals方法,依赖地址值进行判断。* 需求:如果同姓名和同年龄,就认为是同一个学生。所以,需要在自定义的Javabean类中,重写equals方法就可以了。*/System.out.println(coll.contains(s4));}
public class Student {private String name;private int age;public Student() {}public Student(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}@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);}public String toString() {return "Student{name = " + name + ", age = " + age + "}";}
}
2.Collection 的遍历方式
迭代器遍历
迭代器不依赖索引
迭代器在Java中的类是 Iterrator ,迭代器是集合专用的遍历方式。
public static void main(String[] args) {//0.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("aaa");coll.add("bbb");coll.add("ccc");coll.add("ddd");//1.获取迭代器对象Iterator<String> it = coll.iterator();//2.利用循环不断的去获取集合中的每一个元素while (it.hasNext()) {//3.next方法的两件事情:获取元素并移动指针String str = it.next();System.out.println(str);}}
增强for遍历
public static void main(String[] args) {//增强for遍历//0.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("zhangsan");coll.add("lisi");coll.add("wangwu");//1.利用增强for遍历for (String s : coll) {System.out.println(s);}}
Lambda表达式遍历
public static void main(String[] args) {//Lambda 表达式遍历//0.创建集合并添加元素Collection<String> coll = new ArrayList<>();coll.add("zhangsan");coll.add("lisi");coll.add("wangwu");//利用匿名内部类的形式/*底层原理:* 其实也会自己遍历集合,依次得到每一个元素* 把得到的每一个元素,传递给下面的accept方法* s 依次表示集合中的每一个的对象 */coll.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});System.out.println("--------------------------");//1.Lambda表达式遍历coll.forEach(s -> System.out.println(s) );}
3.List集合
List集合的特有方法
public static void main(String[] args) {//0.创建一个集合List<String> list = new ArrayList<>();//1.添加元素list.add("aaa");list.add("bbb");list.add("ccc");//打印集合System.out.println(list); // [aaa, bbb, ccc]System.out.println("-------------------------");//2.在指定位置插入指定的元素list.add(2, "zhangsan");System.out.println(list); // [aaa, bbb, zhangsan, ccc]System.out.println("-------------------------");//3.删除指定索引处的元素,返回被删除的元素/*在调用方法的时候,如果方法出现了重载现象* 优先调用,实参跟形参类型一致的那个方法。*/String remove = list.remove(2);System.out.println(remove); // zhangsanSystem.out.println(list); // [aaa, bbb, ccc]System.out.println("-------------------------");//4.修改指定索引处的元素,返回被修改的元素list.set(0,"狗剩");System.out.println(list); // [狗剩, bbb, ccc]System.out.println("-------------------------");//5.返回指定索引处的元素String s = list.get(1);System.out.println(s); // bbb}
List集合的遍历方式
public static void main(String[] args) {//0.创建集合并添加元素List<String> list = new ArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");//1.迭代器遍历Iterator<String> it = list.iterator();while (it.hasNext()) {String s = it.next();System.out.println(s);}System.out.println("------------------------");//2.增强forfor (String s : list) {System.out.println(s);}System.out.println("------------------------");//3.Lambda 表达式//匿名内部类list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});System.out.println("-------------------------");list.forEach(s -> System.out.println(s));System.out.println("------------------------");//4.普通for循环for (int i = 0; i < list.size(); i++) {String s = list.get(i);System.out.println(s);}System.out.println("-------------------------");//5.列表迭代器ListIterator<String> it2 = list.listIterator();while (it2.hasNext()){String s = it2.next();if ("bbb".equals(s)){it2.add("zhangsan");}System.out.println(s);}System.out.println(list); // [aaa, bbb, zhangsan, ccc]}
五种遍历方式对比
4.数据结构
- 数据结构:计算机存储、组织数据的方式
- 不同的业务场景要选择不同的数据结构。
- 是指数据之间是以什么方式排列在一起的。
- 数据结构是为了更加方便的管理和使用数据,需要结合具体的业务场景来进行选择。
- 一般情况下,精心选择的数据结构可以带来更高的运行或者存储效率。
- 每种数据结构长什么样子?
- 如何添加数据?
- 如何删除数据?
1).栈
栈的特点:后进先出,先进后出
2).队列
队列的特点:先进先出,后进后出
3)数组
- 查询速度快:查询数据通过地址值和索引定位,查询任意数据耗时相同。(元素在内存中是连续存储的)
- 删除效率低:要将原始数据删除,同时后面每个数据前移。
- 添加效率极低:添加位置后的每个数据后移,再添加元素。
**数组是一种查询快,增删慢的模型。
4)链表
- 链表中的结点是独立的对象,在内存中是不连续的,每个结点包含数据值和下一个结点的地址。
- 链表查询慢,无论查询哪个数据都要从头开始找。
- 链表增删相对快。
小结
5)树
6)二叉查找树
前序遍历:
中序遍历:
后序遍历:
层序遍历:
7)平衡二叉树
平衡二叉树旋转机制——左旋
就是将根节点的右侧往左拉,原先的右子节点变成新的父节点,并把多余的左子节点出让,给已经降级的根节点当右子节点
平衡二叉树旋转机制——右旋
就是将根节点的左侧往右拉,左子节点变成了新的父节点,并把多余的右子节点出让,给已经降级根节点当左子节点
平衡二叉树和二叉查找树对比结构图
平衡二叉树需要旋转的四种情况
-
左左
-
左左: 当根节点左子树的左子树有节点插入,导致二叉树不平衡
-
如何旋转: 直接对整体进行右旋即可
-
-
左右
- 左右: 当根节点左子树的右子树有节点插入,导致二叉树不平衡
- 如何旋转: 先在左子树对应的节点位置进行左旋,在对整体进行右旋
-
右右
-
右右: 当根节点右子树的右子树有节点插入,导致二叉树不平衡
-
如何旋转: 直接对整体进行左旋即可
-
-
右左
-
右左:当根节点右子树的左子树有节点插入,导致二叉树不平衡
-
如何旋转: 先在右子树对应的节点位置进行右旋,在对整体进行左旋
-
8)红黑树
平衡二叉树:
- 高度平衡
- 当左右子树高度差超过1时,通过旋转保持平衡
红黑树:
- 是一个二叉查找树
- 但是不是高度平衡的
- 条件:特有的红黑规则
红黑规则:
- 每一个结点或是红色的,或是黑色的
- 根节点必须是黑色
- 如果一个节点没有子节点或者父节点,则该节点相应的指针属性值为 Nil ,这些 Nil 视为叶节点,每个叶节点(Nil)是黑色的
- 如果某一个节点是红色,那么它的子节点必须是黑色(不能出现两个红色节点相连的情况)
- 对每一个结点,从该节点到其所有后代叶节点的简单路径上,均包含相同数目的黑色节点
添加节点的规则
默认颜色:添加节点默认是红色的(效率高)
当默认是黑色时:
当默认是红色时:
红黑树添加节点后如何保持红黑规则
- 根节点位置
- 直接变为黑色
- 非根节点位置
- 父节点为黑色
- 不需要任何操作,默认红色即可
- 父节点为红色
- 叔叔节点为红色
- 将"父节点"设为黑色,将"叔叔节点"设为黑色
- 将"祖父节点"设为红色
- 如果"祖父节点"为根节点,则将根节点再次变成黑色
- 叔叔节点为黑色
- 将"父节点"设为黑色
- 将"祖父节点"设为红色
- 以"祖父节点"为支点进行旋转
- 叔叔节点为红色
- 父节点为黑色
举例:
跳过添加20、18、23
全部添加完成后:
再向其中添加 15 和 14
红黑树增删改查的性能都很好
5.ArrayList集合
1.ArrayList集合底层原理
2.LinkedList集合
3.迭代器底层源码解析
6.泛型深入
1)泛型概述
没有泛型的时候,集合如何存储数据?
public static void main(String[] args) {//没有泛型的时候,集合如何存储数据/*结论:* 如果我们没有给集合指定类型,默认认为所有的数据类型都是Object类型* 此时可以往集合添加任意的数据类型。* 带来一个坏处:我们在获取数据的时候,无法使用它的特有行为。*//*此时推出了泛型 ,可以在添加数据的时候就把类型进行统一。* 而且我们在获取数据的时候,也省的强转了,非常的方便。*///0.创建集合对象ArrayList<Object> list = new ArrayList<>();//1.添加数据list.add(123);list.add("abc");list.add(new Student("zhangsan", 123));//2.遍历集合获取集合中的每一个元素Iterator<Object> it = list.iterator();while (it.hasNext()){Object obj = it.next();//多态的弊端是不能访问子类的特有功能System.out.println(obj);}}
2)泛型类
package Generics;import java.util.Arrays;/** 当在编写一个类的时候,如果不确定类型,那么这个类型就可以定义为泛型类。* */
public class MyArrayList<E> {Object[] obj = new Object[10];int size;public boolean add(E e) {obj[size] = e;size++;return true;}public E get(int index) {return (E) obj[index];}@Overridepublic String toString() {return Arrays.toString(obj);}
}
public static void main(String[] args) {MyArrayList<String> list = new MyArrayList<>();list.add("aaa");list.add("bbb");list.add("ccc");System.out.println(list); // [aaa, bbb, ccc, null, null, null, null, null, null, null]MyArrayList<Integer> list2 = new MyArrayList<>();list2.add(123);list2.add(456);list2.add(789);System.out.println(list2); // [123, 456, 789, null, null, null, null, null, null, null]Integer i = list2.get(0);System.out.println(i); //123}
3)泛型方法
package Generics;import java.util.ArrayList;public class ListUtil {private ListUtil() {}//类中定义一个静态方法addAll,用来添加多个集合的元素。public static <E> void addAll(ArrayList<E> list, E e1, E e2, E e3, E e4) {list.add(e1);list.add(e2);list.add(e3);list.add(e4);}//添加元素个数未知public static <E> void addAll2(ArrayList<E> list, E...e) {for (E element : e) {list.add(element);}}
}
package Generics;import java.util.ArrayList;public class GenericsDemo3 {//定义一个工具类:ListUtil//类中定义一个静态方法addAll,用来添加多个集合的元素。public static void main(String[] args) {ArrayList<String> list = new ArrayList<>();ListUtil.addAll(list, "aaa", "bbb", "ccc","ddd" );System.out.println(list);//[aaa, bbb, ccc, ddd]ArrayList<Integer> list1 = new ArrayList<>();ListUtil.addAll2(list1,1,2,3,4,5,6,7,8,9,3,6,4,2,5);System.out.println(list1);}
}
4)泛型接口
package Generics;import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;public class MyArrayList2 implements List<String> {@Overridepublic int size() {return 0;}@Overridepublic boolean isEmpty() {return false;}@Overridepublic boolean contains(Object o) {return false;}@Overridepublic Iterator<String> iterator() {return null;}@Overridepublic Object[] toArray() {return new Object[0];}@Overridepublic <T> T[] toArray(T[] a) {return null;}@Overridepublic boolean add(String s) {return false;}@Overridepublic boolean remove(Object o) {return false;}@Overridepublic boolean containsAll(Collection<?> c) {return false;}@Overridepublic boolean addAll(Collection<? extends String> c) {return false;}@Overridepublic boolean addAll(int index, Collection<? extends String> c) {return false;}@Overridepublic boolean removeAll(Collection<?> c) {return false;}@Overridepublic boolean retainAll(Collection<?> c) {return false;}@Overridepublic void clear() {}@Overridepublic String get(int index) {return null;}@Overridepublic String set(int index, String element) {return null;}@Overridepublic void add(int index, String element) {}@Overridepublic String remove(int index) {return null;}@Overridepublic int indexOf(Object o) {return 0;}@Overridepublic int lastIndexOf(Object o) {return 0;}@Overridepublic ListIterator<String> listIterator() {return null;}@Overridepublic ListIterator<String> listIterator(int index) {return null;}@Overridepublic List<String> subList(int fromIndex, int toIndex) {return null;}
}
public static void main(String[] args) {/*泛型接口的两种使用方式:* 1.实现类给出具体的类型* 2.实现类延续泛型,创建实现类对象时再确定类型 */MyArrayList2 list = new MyArrayList2();list.add("abc");//list.add(123); // java: 不兼容的类型: int无法转换为java.lang.String}
5)泛型的继承和通配符
- 泛型不具备继承性,但是数据具备继承性
- 泛型里面写的是什么类型,那么在方法中只能传递什么类型的数据。、
package Generics.Test;public abstract class Animal {/*属性:名字,年龄行为:吃东西*/private String name;private int age;public Animal() {}public Animal(String name, int age) {this.name = name;this.age = age;}/*** 获取* @return name*/public String getName() {return name;}/*** 设置* @param name*/public void setName(String name) {this.name = name;}/*** 获取* @return age*/public int getAge() {return age;}/*** 设置* @param age*/public void setAge(int age) {this.age = age;}public abstract void eat();public String toString() {return "Animal{name = " + name + ", age = " + age + "}";}
}
package Generics.Test;public abstract class Cat extends Animal{
}
package Generics.Test;public abstract class Dog extends Animal{
}
package Generics.Test;public class PersianCat extends Cat {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的波斯猫,正在吃小饼干");}
}
package Generics.Test;public class LiHuaCat extends Cat {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的狸花猫,正在吃鱼");}
}
package Generics.Test;public class HuskyDog extends Dog {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的哈士奇,正在吃骨头,边吃边拆家");}
}
package Generics.Test;public class TeddyDog extends Dog {@Overridepublic void eat() {System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的泰迪,正在吃骨头,边吃边蹭");}
}
public static void main(String[] args) {/*需求:定义一个继承结构:动物| |猫 狗| | | |波斯猫 狸花猫 泰迪 哈士奇属性:名字,年龄行为:吃东西波斯猫方法体打印:一只叫做XXX的,X岁的波斯猫,正在吃小饼干狸花猫方法体打印:一只叫做XXX的,X岁的狸花猫,正在吃鱼泰迪方法体打印:一只叫做XXX的,X岁的泰迪,正在吃骨头,边吃边蹭哈士奇方法体打印:一只叫做XXX的,X岁的哈士奇,正在吃骨头,边吃边拆家测试类中定义一个方法用于饲养动物public static void keepPet(ArrayList<???> list){//遍历集合,调用动物的eat方法}要求1:该方法能养所有品种的猫,但是不能养狗要求2:该方法能养所有品种的狗,但是不能养猫要求3:该方法能养所有的动物,但是不能传递其他类型*/ArrayList<PersianCat> list1 = new ArrayList<>();ArrayList<LiHuaCat> list2 = new ArrayList<>();ArrayList<TeddyDog> list3 = new ArrayList<>();ArrayList<HuskyDog> list4 = new ArrayList<>();keepPet(list1);keepPet(list2);keepPet(list3);keepPet(list4);}//要求3:该方法能养所有的动物,但是不能传递其他类型public static void keepPet(ArrayList<? extends Animal> list){}//要求2:该方法能养所有品种的狗,但是不能养猫/*public static void keepPet(ArrayList<? extends Dog> list){}*///要求1:该方法能养所有品种的猫,但是不能养狗/*public static void keepPet(ArrayList<? extends Cat> list){}*/
总结
7.Set系列集合
- 不可以存储重复元素
- 没有索引,不能使用普通for循环遍历
- 无序:存取顺序不一致
- 不重复:可以去除重复
- 无索引:没有带索引的方法,所以不能使用普通for循环遍历,也不能通过索引来获取元素
Set 集合的实现类
- HashSet :无序、不重复、无索引
- LinkedHashSet:有序、不重复、无索引
- TreeSet:可排序、不重复、无索引
Set 接口中的方法上基本上与Collection的API一致
public static void main(String[] args) {/*练习 存储字符串并遍历* 利用Set系列的集合,添加字符串,并使用多种方式遍历* 0.迭代器* 1.增强for* 2.Lambda表达式*///0.创建Set集合的对线Set<String> s = new HashSet<>();//1.添加元素/*如果当前元素是第一次添加,那么可以添加成功,返回true* 如果当前元素是第二次添加,那么添加失败,返回false*/s.add("张三");s.add("李四");s.add("王五");//2.打印集合System.out.println(s); // [李四, 张三, 王五]//迭代器遍历Iterator<String> it = s.iterator();while (it.hasNext()) {String s1 = it.next();System.out.println(s1);}System.out.println("==========================");//增强for遍历for (String s2 : s) {System.out.println(s2);}System.out.println("=========================");//Lambda 表达式/*s.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});*/s.forEach(s3 -> System.out.println(s3));}
1)HashSet
HashSet 底层原理
- HashSet 集合底层采取哈希表存储数据
- 哈希表是一种对于增删改查数据性能都较好的结构
哈希表组成
- JDK8之前:数组+链表
- JDK8开始:数组+链表+红黑树
哈希值:对象的整数表现形式
哈希值:
- 根据hashCode方法计算出来的int类型的整数
- 该方法定义在Object类中,所有对象都可以调用,默认使用地址值进行计算
- 一般情况下,会重写hashCode方法,利用对象内部的属性值计算哈希值
public static void main(String[] args) {//0.创建对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("zhangsan", 23);//1.如果没有重写hashCode方法,不同对象计算处的哈希值是不同的System.out.println(s1.hashCode()); // 990368553System.out.println(s2.hashCode()); // 1096979270//2.如果已经重写hashCode方法,不同的对象只要属性值相同,计算处的哈希值就是一样的System.out.println(s1.hashCode()); // -1461067292System.out.println(s2.hashCode()); // -1461067292//3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)System.out.println("abc".hashCode()); // 96354System.out.println("acD".hashCode()); // 96354}
public static void main(String[] args) {//0.创建学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 14);Student s3 = new Student("wangwu", 26);Student s4 = new Student("zhangsan", 23);//1.创建集合用来添加学生HashSet<Student> hs = new HashSet<>();//2.添加数据System.out.println(hs.add(s1)); //trueSystem.out.println(hs.add(s2)); //trueSystem.out.println(hs.add(s3)); //trueSystem.out.println(hs.add(s4)); //falseSystem.out.println(hs);}
package Set;import java.util.Objects;public 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 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);}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
2)LinkedHashSet
public static void main(String[] args) {//0.创建学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 14);Student s3 = new Student("wangwu", 26);Student s4 = new Student("zhangsan", 23);//1.创建集合用来添加学生LinkedHashSet<Student> lhs = new LinkedHashSet<>();//2.添加数据System.out.println(lhs.add(s1)); //trueSystem.out.println(lhs.add(s2)); //trueSystem.out.println(lhs.add(s3)); //trueSystem.out.println(lhs.add(s4)); //falseSystem.out.println(lhs); //[Student{name='zhangsan', age=23}, Student{name='lisi', age=14}, Student{name='wangwu', age=26}]}
3)TreeSet
public static void main(String[] args) {/*需求:* 存储整数并进行排序 *///0.创建TreeSet集合对象TreeSet<Integer> ts = new TreeSet<>();//1.添加数据ts.add(4);ts.add(5);ts.add(2);ts.add(1);ts.add(3);//2.打印集合System.out.println(ts); // [1, 2, 3, 4, 5]//3.遍历//迭代器Iterator<Integer> it = ts.iterator();while (it.hasNext()) {Integer num = it.next();System.out.println(num);}System.out.println("=================");//加强forfor (Integer t : ts) {System.out.println(t);}System.out.println("======================");//Lambda表达式ts.forEach(num -> System.out.println(num));
public static void main(String[] args) {/*需求:* 创建TreeSet集合,并添加3个学生对象* 学生对象属性:* 姓名、年龄* 要求按照学生的年龄进行排序* 同年龄按照姓名字母排列(暂不考虑中文)* 同姓名,同年龄认为是同一个人** 方式一:* 默认的排序规则/自然排序* Student实现Comparable接口,重写里面的抽象方法,再指定比较规则** 方式二:* 比较器排序* 创建TreeSet对象的时候,传递比较器Comparator指定规则*///0.创建学生对象Student s1 = new Student("zhangsan", 23);Student s2 = new Student("lisi", 24);Student s3 = new Student("wangwu", 25);//1.创建集合对象TreeSet<Student> ts = new TreeSet<>();//2.添加数据ts.add(s2);ts.add(s1);ts.add(s3);//3.打印数据System.out.println(ts);}
package Set;import java.util.Objects;public class Student implements Comparable<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 +'}';}@Overridepublic int compareTo(Student o) {int res = this.getAge() - o.getAge();return res;}
}
public static void main(String[] args) {/** 需求:请自行选择比较器排序和自然排序两种方式:* 要求:存入四个字符串,c , ab , df , qwer* 按照长度排序,如果一样长则按照首字母排序*///0.创建集合/*o1:表示当前要添加的元素* o2:表示已经在红黑树存在的元素* 返回值:* 负数:认为要添加的元素是小的,存左边* 正数:认为要添加的元素是大的,存右边* 0:认为要添加的元素已经存在,舍弃*//*TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//按照长度排序int i = o1.length() - o2.length();//如果一样长则按照首字母排序i = i == 0 ? o1.compareTo(o2) : i;return i;}});*/TreeSet<String> ts = new TreeSet<>((o1, o2) -> {//按照长度排序int i = o1.length() - o2.length();//如果一样长则按照首字母排序i = i == 0 ? o1.compareTo(o2) : i;return i;});//添加数据ts.add("c");ts.add("ab");ts.add("df");ts.add("qwer");//打印System.out.println(ts); // [c, ab, df, qwer]}
package Set;public class Student2 implements Comparable<Student2> {/*属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)*/private String name;private int age;private int Chinese;private int Math;private int English;public Student2() {}public Student2(String name, int age, int Chinese, int Math, int English) {this.name = name;this.age = age;this.Chinese = Chinese;this.Math = Math;this.English = English;}/*** 获取** @return name*/public String getName() {return name;}/*** 设置** @param name*/public void setName(String name) {this.name = name;}/*** 获取** @return age*/public int getAge() {return age;}/*** 设置** @param age*/public void setAge(int age) {this.age = age;}/*** 获取** @return Chinese*/public int getChinese() {return Chinese;}/*** 设置** @param Chinese*/public void setChinese(int Chinese) {this.Chinese = Chinese;}/*** 获取** @return Math*/public int getMath() {return Math;}/*** 设置** @param Math*/public void setMath(int Math) {this.Math = Math;}/*** 获取** @return English*/public int getEnglish() {return English;}/*** 设置** @param English*/public void setEnglish(int English) {this.English = English;}public String toString() {return "Student2{name = " + name + ", age = " + age + ", Chinese = " + Chinese + ", Math = " + Math + ", English = " + English + "}";}/*按照总分从高到低输出到控制台* 如果总分一样,按照语文成绩排* 如果语文一样,按照数学成绩排* 如果数学成绩一样,按照英语成绩排* 如果英语成绩一样,按照年龄排* 如果年龄一样,按照姓名的字母顺序排* 如果都一样,认为是同一个学生,不存*/@Overridepublic int compareTo(Student2 o) {int sum1 = this.getChinese() + this.getMath() + this.getEnglish();int sum2 = o.getChinese() + o.getMath() + o.getEnglish();//比较总分int i = sum1 - sum2;//果总分一样,按照语文成绩排i = i == 0 ? this.getChinese() - o.getChinese() : i;//如果语文一样,按照数学成绩排i = i == 0 ? this.getMath() - o.getMath() : i;//如果数学成绩一样,按照英语成绩排(可以省略不写)i = i == 0 ? this.getEnglish() - o.getEnglish() : i;//如果英语成绩一样,按照年龄排i = i == 0 ? this.getAge() - o.getAge() : i;//如果年龄一样,按照姓名的字母顺序排i = i == 0 ? this.getName().compareTo(o.getName()) : i;return i;}
}
public static void main(String[] args) {/*需求:创建5个学生对象* 属性:(姓名、年龄、语文成绩、数学成绩、英语成绩)* 按照总分从高到低输出到控制台* 如果总分一样,按照语文成绩排* 如果语文一样,按照数学成绩排* 如果数学成绩一样,按照英语成绩排* 如果英语成绩一样,按照年龄排* 如果年龄一样,按照姓名的字母顺序排* 如果都一样,认为是同一个学生,不存。*///0.创建5个学生对象Student2 s1 = new Student2("zhangsan", 23, 90, 99, 50);Student2 s2 = new Student2("lisi", 24, 90, 98, 50);Student2 s3 = new Student2("wangwu", 25, 95, 100, 30);Student2 s4 = new Student2("zhaoliu", 26, 60, 99, 70);Student2 s5 = new Student2("qianqi", 26, 70, 80, 70);//1.创建集合TreeSet<Student2> ts = new TreeSet<>();//2.添加数据ts.add(s1);ts.add(s2);ts.add(s3);ts.add(s4);ts.add(s5);//3.打印//System.out.println(ts);Iterator<Student2> it = ts.iterator();while (it.hasNext()) {Student2 info = it.next();int sum = info.getChinese() + info.getMath() + info.getEnglish();System.out.println(info + " 总分:" + sum);}/*Student2{name = qianqi, age = 26, Chinese = 70, Math = 80, English = 70} 总分:220Student2{name = wangwu, age = 25, Chinese = 95, Math = 100, English = 30} 总分:225Student2{name = zhaoliu, age = 26, Chinese = 60, Math = 99, English = 70} 总分:229Student2{name = lisi, age = 24, Chinese = 90, Math = 98, English = 50} 总分:238Student2{name = zhangsan, age = 23, Chinese = 90, Math = 99, English = 50} 总分:239*/}
8.单列集合使用场景
相关文章:

十三、集合进阶——单列集合 及 数据结构
单列集合 及 数据结构 13.1 集合体系结构13.1.2 单列集合1. Collection2.Collection 的遍历方式迭代器遍历增强for遍历Lambda表达式遍历 3.List集合List集合的特有方法List集合的遍历方式五种遍历方式对比 4.数据结构1).栈2).队列3)数组4)链表小结5&…...

Android | ArcGIS入门
一、概述 ArcGIS是由Esri开发的地理信息系统(GIS)软件。它用于制图、空间分析和数据可视化。ArcGIS允许用户以各种格式创建、管理、分析和共享地理信息。它通常用于城市规划、环境管理和应急响应等领域。该软件包括一系列工具,用于创建地图、…...

dockerfile文件书写
1.dockerfile构建nginx镜像 1.1书写dockerfile文件 mkdir nginx #创建nginx目录 cd nginx vim dockerfile # 修改文件FROM centos # 基础镜像,默认最新的centos8操作系统 MAINTAINER xianchao # 指定镜像的作者信息 RUN rm -rf /etc/yum.repos.d/* # centos8默认…...

蓝桥杯-整数删除
给定一个长度为 N 的整数数列:A1, A2, ... , AN。你要重复以下操作 K 次: 每次选择数列中最小的整数(如果最小值不止一个,选择最靠前的),将其删除。 并把与它相邻的整数加上被删除的数值。 输出 K 次操作后…...

以程序员的视角,看前后端分离的是否必要?
Hello,我是贝格前端工场,本篇分享一个老生常谈的话题,前后端分离是必然趋势,但也是要区分具体的场景,欢迎探讨,关注,有前端开发需求可以私信我,上车了。 一、什么是前后端分离和不分…...

Linux:sed进阶(12)
Linux:shell脚本:基础使用(5)《正则表达式-sed工具》_linux脚本表达式s-CSDN博客https://blog.csdn.net/w14768855/article/details/132347574?ops_request_misc%257B%2522request%255Fid%2522%253A%252217084222871680019707523…...

Linux命令-builtin命令(执行bash内建命令)
说明 用于执行指定的bash内建命令。builtin 命令调用的bash内建命令优先于同名的外部命令及同名的shell函数。 语法 builtin [shell-builtin [arg ...]]参数 shell-builtin(可选):要调用的bash内建命令。 arg(可选)…...

HTML的特殊字符
HTML的特殊字符 有些特殊的字符在 html 文件中是不能直接表示的,例如: 空格,小于号(<),大于号(>),按位与(&)。 空格 示例代码: 运行结果: 由于html 标签就是用 < > 表示的࿰…...

内核移植学习
内核移植 内核移植就是指将RT-Thread内核在不同的芯片架构、不同的板卡上运行起来。 移植可分为CPU架构移植和BSP板级支持包移植两部分。 CPU架构移植 在嵌入式领域有多种不同CPU架构,例如Cortex-M、ARM920T、MIPS32、RISC-V等等。 为了使RT-Thread能够在不同C…...

Mysql 两个日期相减得到指定的格式数据
首先避坑: Mysql 中两个日期直接相减,若在同一天则得到的是秒,否则相减得到的并不是秒,一定要注意。 函数 TIMESTAMPDIFF(unit,begin,end); 函数返回 begin - end 的结果。 其中 begin 和 end 是 DATE 或 DATETIME 表达式。 …...

第六十四天 服务攻防-框架安全CVE复现Apache shiroApache Solr
第六十四天 服务攻防-框架安全&CVE复现Apache shiro&Apache Solr 知识点: 中间件及框架列表: IIS,Apache,Nginx,Tomcat,Docker,K8s,Weblogic.JBoos,WebSphere, Jenkins,GlassFish,Jetty,Jira,Struts2,Laravel,Solr,Shiro,Thinkphp,Spring, Flask,jQuery等 1、开发框…...

JavaScript 设计模式之享元模式
享元 将一部分共用的方法提取出来作为公用的模块 const Car {getName: function () {return this.name},getPrice: function (price) {return price * 30} }const BMW function (name, price) {this.name namethis.price price } BMW.prototype Car const bmw new BMW(…...

利用故事推动企业变革:如何提升数据分析技能
单一的数据和表格尽管有算法的支撑,但在其表达方式上总会让人感到头疼。当我们需要深入了解企业的盈利能力,或是尝试评估业务的增长机会时,以往都会将精力全部放在分析数字、阅读信息、回顾历史和沟通交流之上,却忽略随之而生成的…...

Python内置函数04——enumerate
文章目录 概述语法实例展示 概述 在Python中,enumerate()是一个很常用的内置函数。它的作用是将一个可迭代对象(如列表、元组、字符串等)组合为一个索引序列和元素序列的枚举对象。 语法 enumerate(iterable, start0) 其中,ite…...

unity学习(28)——登录功能
有之前注册的知识,登录就很容易处理了。 登陆成功返回id: 登录失败返回null: 测试同一账号不能重复登陆!登录成功后最好可以跳到新的场景中 结果是好的,去服务器看一下对应部分的代码,可见,登…...

Mac公证脚本-Web公证方式
公证方式 Mac 公证方式有三种 公证方法 优点 缺点 阐述 Xcode Xcode携带的图形界面,使用方便 无法进行自动化公证 单个App应用上架使用较多 altool(旧版) 支持pkg,dmg,脚本自动化 2023/11/01 将会过期 已经…...

让你专注工作的思维模板,进入每天的专注生活
开启专注生活,打造高效氛围,踏上传奇之路。 如何专注工作? 阻止内部干扰阻止外部干扰结论 专注象限图如下:(幸福是一种不断增加难度的活动) A1是你开始做某事的时候。 A2是当任务变得过于简单的时候。 A3是…...

Java之获取Nginx代理之后的客户端IP
Java之获取Nginx代理之后的客户端IP Nginx代理接口之后,后台获取的IP地址都是127.0.0.1,解决办法是需要配置Nginx搭配后台获取的方法,获得设备的真实地址。我们想要获取的就是nginx代理日志中的这个IP nginx配置 首先在nginx代理的对应lo…...

【springboot+vue项目(十五)】基于Oauth2的SSO单点登录(二)vue-element-admin框架改造整合Oauth2.0
Vue-element-admin 是一个基于 Vue.js 和 Element UI 的后台管理系统框架,提供了丰富的组件和功能,可以帮助开发者快速搭建现代化的后台管理系统。 一、基本知识 (一)Vue-element-admin 的主要文件和目录 vue-element-admin/ |…...

音频的传输链路与延迟优化点
麦克风->系统采集模块->APP采集模块->3A、混响等音效->混音->音频编码->RTC网络发送-> MediaServer->RTC网络接收->音频jitter buffer->音频解码->音频的后处理(均衡)->APP播放模块->x系统播放模块->扬声器/耳机。 整个链路如上&a…...

【51单片机】直流电机驱动(PWM)(江科大)
1.直流电机介绍 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极,当电极正接时,电机正转,当电极反接时,电机反转 直流电机主要由永磁体(定子)、线圈(转子)和换向器组成 除直流电机外,常见的电机还有步进电机、舵机、无刷电机、空心杯电机等 2.电机驱动…...

腾讯文档(excel也一样)设置单元格的自动行高列宽
1. 选中单元格 可选择任意一个或者几个 2. 设置自动 行高和列宽 即可生效...

vue-router 提供的几种导航守卫
vue-router 提供的导航守卫主要用来通过跳转或取消的方式守卫导航。这里有很多方式植入路由导航中:全局的,单个路由独享的,或者组件级的。 1、全局前置守卫 你可以使用 router.beforeEach 注册一个全局前置守卫: const route…...

Element UI 组件的安装及使用
Element UI 组件的安装及使用 Element UI 是一套基于 Vue.js 的桌面端 UI 组件库,提供了丰富的、高质量的 UI 组件,可以帮助开发者快速构建用户界面。 1、安装 Element UI 使用 npm 安装 npm install element-ui -S2、使用 CDN 安装 在 HTML 页面中引…...

网站架构演变、LNP+Mariadb数据库分离、Web服务器集群、Keepalived高可用
目录 day02 深入理解程序的数据存储 验证 配置NFS服务器 配置代理服务器 配置名称解析 day02 深入理解程序的数据存储 程序将文字数据保存到数据库中程序将非文字数据(如图片、视频、压缩包等)保存到相应的文件目录中 验证 发一篇文章…...

设计模式(七):策略模式(行为型模式)
FullDiscount Strategy,策略模式:定义一系列的算法,把他们一个个封装起来, 并使他们可以互相替换,本模式使得算法可以独立于使用它们的客户。 场景:购物车结算时,根据不同的客户,…...

人工智能|深度学习——基于对抗网络的室内定位系统
代码下载: 基于CSI的工业互联网深度学习定位.zip资源-CSDN文库 摘要 室内定位技术是工业互联网相关技术的关键一环。该技术旨在解决于室外定位且取得良好效果的GPS由于建筑物阻挡无法应用于室内的问题。实现室内定位技术,能够在真实工业场景下实时追踪和…...

MySQL的配置文件my.cnf正常的配置项目
my.cnf(或my.ini)是MySQL的配置文件,其中包含了多种设置,用于控制MySQL服务器的运行方式。以下是my.cnf中一些常见的配置项目: 服务器设置 - [mysqld]:服务器的配置部分。 - user:指定M…...

小程序API能力集成指南——界面导航栏API汇总
ty.setNavigationBarColor 设置页面导航条颜色 需引入MiniKit,且在>2.0.0版本才可使用 参数 Object object 属性类型默认值必填说明frontColorstring是前景颜色值,包括按钮、标题、状态栏的颜色,仅支持 #ffffff 和 #000000backgroundCo…...

onlyoffice基础环境搭建+部署+demo可直接运行 最简单的入门
office这个体系分为四个大教程 1、【document server文档服务器基础搭建】 2、【连接器(connector)或者jsApi调用操作office】-进阶 3、【document builder文档构造器使用】-进阶 4、【Conversion API(文档转化服务)】-进阶 如果需要连接器,可以查看:onl…...