单列集合 及 数据结构
- 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")); //false
System.out.println(coll.contains("bbb")); // true
System.out.println("------------------------------------------");
//4.判断是否为空
System.out.println("-------------3.判断元素是否包含-------------");
System.out.println(coll.isEmpty()); //false
System.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;
}
@Override
public 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>() {
@Override
public 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); // zhangsan
System.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.增强for
for (String s : list) {
System.out.println(s);
}
System.out.println("------------------------");
//3.Lambda 表达式
//匿名内部类
list.forEach(new Consumer<String>() {
@Override
public 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];
}
@Override
public 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> {
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<String> iterator() {
return null;
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public <T> T[] toArray(T[] a) {
return null;
}
@Override
public boolean add(String s) {
return false;
}
@Override
public boolean remove(Object o) {
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
return false;
}
@Override
public boolean addAll(Collection<? extends String> c) {
return false;
}
@Override
public boolean addAll(int index, Collection<? extends String> c) {
return false;
}
@Override
public boolean removeAll(Collection<?> c) {
return false;
}
@Override
public boolean retainAll(Collection<?> c) {
return false;
}
@Override
public void clear() {
}
@Override
public String get(int index) {
return null;
}
@Override
public String set(int index, String element) {
return null;
}
@Override
public void add(int index, String element) {
}
@Override
public String remove(int index) {
return null;
}
@Override
public int indexOf(Object o) {
return 0;
}
@Override
public int lastIndexOf(Object o) {
return 0;
}
@Override
public ListIterator<String> listIterator() {
return null;
}
@Override
public ListIterator<String> listIterator(int index) {
return null;
}
@Override
public 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 {
@Override
public void eat() {
System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的波斯猫,正在吃小饼干");
}
}
package Generics.Test;
public class LiHuaCat extends Cat {
@Override
public void eat() {
System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的狸花猫,正在吃鱼");
}
}
package Generics.Test;
public class HuskyDog extends Dog {
@Override
public void eat() {
System.out.println("一只叫做" + getName() + "的," + getAge() + "岁的哈士奇,正在吃骨头,边吃边拆家");
}
}
package Generics.Test;
public class TeddyDog extends Dog {
@Override
public 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>() {
@Override
public 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()); // 990368553
System.out.println(s2.hashCode()); // 1096979270
//2.如果已经重写hashCode方法,不同的对象只要属性值相同,计算处的哈希值就是一样的
System.out.println(s1.hashCode()); // -1461067292
System.out.println(s2.hashCode()); // -1461067292
//3.但是在小部分情况下,不同的属性值或者不同的地址值计算出来的哈希值也有可能一样。(哈希碰撞)
System.out.println("abc".hashCode()); // 96354
System.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)); //true
System.out.println(hs.add(s2)); //true
System.out.println(hs.add(s3)); //true
System.out.println(hs.add(s4)); //false
System.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;
}
@Override
public 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);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public 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)); //true
System.out.println(lhs.add(s2)); //true
System.out.println(lhs.add(s3)); //true
System.out.println(lhs.add(s4)); //false
System.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("=================");
//加强for
for (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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public 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>() {
@Override
public 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 + "}";
}
/*按照总分从高到低输出到控制台
* 如果总分一样,按照语文成绩排
* 如果语文一样,按照数学成绩排
* 如果数学成绩一样,按照英语成绩排
* 如果英语成绩一样,按照年龄排
* 如果年龄一样,按照姓名的字母顺序排
* 如果都一样,认为是同一个学生,不存*/
@Override
public 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} 总分:220
Student2{name = wangwu, age = 25, Chinese = 95, Math = 100, English = 30} 总分:225
Student2{name = zhaoliu, age = 26, Chinese = 60, Math = 99, English = 70} 总分:229
Student2{name = lisi, age = 24, Chinese = 90, Math = 98, English = 50} 总分:238
Student2{name = zhangsan, age = 23, Chinese = 90, Math = 99, English = 50} 总分:239*/
}
8.单列集合使用场景