目录
思维导图
一.set集合特点&遍历方式
set集合的特点:不重复基本数据类型
&字符串常量 String str=“abc”;
&引用对象 String str = new String();
代码块:
package com.jiangwenjuan.set;
import java.util.HashSet;
import java.util.Iterator;
/**
* set集合的特点
* 不重复,基本数据类型&String = "acb"; &String str = new String();
*
*
* @author 蒋文娟
*
* @date 2022年6月8日 下午4:42:02
*/
public class Demo1 {
public static void main(String[] args) {
HashSet set = new HashSet<>();
set.add("zs");
set.add("ls");
set.add("ww");
set.add("老六");
set.add("ls");
System.out.println(set.size());
System.out.println("========增强for==========");
for (Object obj : set) {
System.out.println(obj);
}
System.out.println("========迭代器==========");
Iterator it = set.iterator();
while(it.hasNext()) {
System.out.println(it.next());
}
}
}
结果:
4
========增强for==========
ww
老六
ls
zs
========迭代器==========
ww
老六
ls
zs
二.set集合去重原理
set底层去重原理:
1.set去重底层原理是与对象的hashCode以及equals方法相关
2.判断重复元素的时候,是先比较hashCode值,在调用equals比较内容
①.set去重底层原理是与对象的hashCode以及equals方法相关
代码块:
package com.jiangwenjuan.set;
import java.util.HashSet;
/**
* @author 蒋文娟
*
* @date 2022年6月8日 下午6:05:43
*/
public class Demo2 {
public static void main(String[] args) {
HashSet set = new HashSet<>();
set.add(new Person("zs", 18));
set.add(new Person("ls", 14));// distrinct 在我们手里的时候可以去重,在别人就不能
set.add(new Person("ww", 24));// 用set去重
set.add(new Person("老六", 22));
set.add(new Person("zs", 18));
System.out.println(set.size());
}
}
class Person{
private String name;
private int 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;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
// TODO Auto-generated constructor stub
}
@Override
public int hashCode() {
System.out.println("===========hashCode===========");
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result ;
}
@Override
public boolean equals(Object obj) {
System.out.println("===========equals===========");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
结果:
===========hashCode===========
===========hashCode===========
===========hashCode===========
===========hashCode===========
===========hashCode===========
===========equals===========
4
如果hashCode哪里返回的是1的话,结果为一样也为四:
===========hashCode===========
===========hashCode===========
===========equals===========
===========hashCode===========
===========equals===========
===========equals===========
===========hashCode===========
===========equals===========
===========equals===========
===========equals===========
===========hashCode===========
===========equals===========
4
②、判断重复元素的时候,是先比较hashCode值,在调用equals比较内容
package com.jiangwenjuan.set;
import java.util.HashSet;
/**
* set底层去重原理
* 1.set去重底层原理是与对象的hashCode以及equals方法相关
* 2.判断重复元素的时候,是先比较hashCode值,在调用equals比较内容
*
* @author 蒋文娟
*
* @date 2022年6月8日 下午6:05:43
*/
public class Demo2 {
public static void main(String[] args) {
HashSet set = new HashSet<>();
set.add(new Person("zs", 18));
set.add(new Person("ls", 14));// distrinct 在我们手里的时候可以去重,在别人就不能
set.add(new Person("ww", 24));// 用set去重
set.add(new Person("老六", 22));
set.add(new Person("zs", 18));
System.out.println(set.size());
}
}
class Person{
private String name;
private int 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;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
// TODO Auto-generated constructor stub
}
@Override
public int hashCode() {
System.out.println("===========hashCode===========");
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return 1;
}
@Override
public boolean equals(Object obj) {
System.out.println("===========equals===========");
// if (this == obj)
// return true;
// if (obj == null)
// return false;
// if (getClass() != obj.getClass())
// return false;
// Person other = (Person) obj;
// if (age != other.age)
// return false;
// if (name == null) {
// if (other.name != null)
// return false;
// } else if (!name.equals(other.name))
// return false;
return true;
}
}
③、这两个的区别就在于,一个是为4,一个为1
set.add(new Person("zs", 18));
set.add(new Person("ls", 14));
set.add(new Person("ww", 24));
set.add(new Person("老六", 22));
set.add(new Person("zs", 18));
原理1:第一个加进去时候不需要比较,当第二加进去的时候,就跟第一个比较一次,再第三个加进去的时候比较两次,以此类推,当第五个加进去的时候就比较四次了。
equals的判断要留下。
原理2:当hasCode为1的时候,equals也为true的时候,就判定为了一个元素。
底层的基础原理就两个:先调用hashCode的值,相等,在去比equals,如果hashCode都不相等,就不会去调用equals方法了。
@Override
public int hashCode() {
System.out.println("===========hashCode===========");
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return 1;
}
@Override
public boolean equals(Object obj) {
System.out.println("===========equals===========");
// if (this == obj)
// return true;
// if (obj == null)
// return false;
// if (getClass() != obj.getClass())
// return false;
// Person other = (Person) obj;
// if (age != other.age)
// return false;
// if (name == null) {
// if (other.name != null)
// return false;
// } else if (!name.equals(other.name))
// return false;
return true;
}
三.set集合自然排序接口
①.需求:从xxx公司,拿到用户数据,需要根据用户的级别,进行会议座位的排序
张三 部门总监 1
李四 普通员工 3
王五 部门经理 2。。
现象:1.String默认是能够排序的
2.自定义的对象无法排序,报类型转换异常
实体类:
class Person implements Comparable<Person>{
private String name;
private int age;
private int level;
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 Person(String name, int age, int level) {
super();
this.name = name;
this.age = age;
this.level = level;
}
public int getLevel() {
return level;
}
public void setLevel(int level) {
this.level = level;
}
public Person() {
// TODO Auto-generated constructor stub
}
@Override
public int hashCode() {
System.out.println("===========hashCode===========");
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return 1;
}
@Override
public boolean equals(Object obj) {
System.out.println("===========equals===========");
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
return this.level - o.level;
}
代码块:
package com.jiangwenjuan.set;
import java.util.TreeSet;
/**
* set集合排序
* @author 蒋文娟
*
* @date 2022年6月8日 下午6:52:23
*/
public class Demo3 {
public static void main(String[] args) {
/**
* 张三 部门总监 1
* 李四 普通员工 3
* 王五 部门经理 2
* 。。
* xxxService.list(1);
*
* 现象:
* 1.String默认是能够排序的
* 2.自定义的对象无法排序,报类型转换异常
*/
// Exception in thread "main" java.lang.ClassCastException: 类型转换异常
// com.jiangwenjuan.set.Person cannot be cast to java.lang.Comparable
// 这个Person的类不能强制转换为Comparable接口
TreeSet set = new TreeSet<>();
set.add(new Person("张三", 18, 1));
set.add(new Person("李四", 24, 4));
set.add(new Person("王五", 26, 2));
set.add(new Person("老六", 20, 3));
for (Object Object : set) {
System.out.println(Object);
}
}
}
这里就已经按会议座位排序了,结果:
Person [name=张三, age=18, level=1]
Person [name=王五, age=26, level=2]
Person [name=老六, age=20, level=3]
Person [name=李四, age=24, level=4]
②.需求:按照年龄升序,打印出人员信息
主要是要修改实体类中重写的compareTo方法
实体类: 这里也按照了年龄和等级的比较
@Override
public int compareTo(Person o) {
int levelRes = this.level - o.level;
return levelRes == 0 ? this.age - o.age:levelRes;
}
代码块:多加了一个八戒
TreeSet set = new TreeSet<>();
set.add(new Person("张三", 18, 1));
set.add(new Person("李四", 24, 4));
set.add(new Person("王五", 26, 2));
set.add(new Person("老六", 20, 3));
set.add(new Person("八戒", 18, 3));
for (Object Object : set) {
System.out.println(Object);
}
结果为:
Person [name=张三, age=18, level=1]
Person [name=王五, age=26, level=2]
Person [name=八戒, age=18, level=3]
Person [name=老六, age=20, level=3]
Person [name=李四, age=24, level=4]
③.需求:按照用户的首字母排序以及上面两个需求,都要满足
set集合排序
1. java.lang.Comparable:自然排序 排序的规则是单一的,不能够应对复杂的变化的需求
2. java.util.comparator:比较器排序
专门用来做比较的
TreeSet set = new TreeSet<>(comparator)
实体类的实现implements Comparable<Person>
把它注释掉,最后的compareTo
也注释掉。
这里有的小问题那是因为代码问题:
代码块:
package com.jiangwenjuan.set;
import java.util.Comparator;
import java.util.TreeSet;
/**
* @author 蒋文娟
*
* @date 2022年6月8日 下午6:52:23
*/
public class Demo3 {
public static void main(String[] args) {
/**
* 需求1:从xxx公司,拿到用户数据,需要根据用户的级别,进行会议座位的排序
*
* 需求2:
* 按照年龄升序,打印出人员信息
*
* 需求3:
* 按照用户的首字母排序
*/
// Exception in thread "main" java.lang.ClassCastException: 类型转换异常
// com.jiangwenjuan.set.Person cannot be cast to java.lang.Comparable
// 这个Person的类不能强制转换为Comparable接口
TreeSet set = new TreeSet<>(new levelCompartor());
set.add(new Person("张三", 18, 1));
set.add(new Person("李四", 24, 4));
set.add(new Person("王五", 26, 2));
set.add(new Person("老六", 20, 3));
set.add(new Person("八戒", 18, 3));
for (Object Object : set) {
System.out.println(Object);
}
}
}
class levelCompartor implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
return o1.getLevel() - o2.getLevel();
}
}
然而这里的结果是只有四个,那是因为代码问题:
Person [name=张三, age=18, level=1]
Person [name=王五, age=26, level=2]
Person [name=老六, age=20, level=3]
Person [name=李四, age=24, level=4]
怎么解决呢?就是按照我们之前的哪个写法一样的
class levelCompartor implements Comparator<Person>{
@Override
public int compare(Person o1, Person o2) {
int levelRes = o1.getLevel() - o2.getLevel();
return levelRes == 0?o1.getAge() - o2.getAge():levelRes;
}
}
结果就出来了:
Person [name=张三, age=18, level=1]
Person [name=王五, age=26, level=2]
Person [name=八戒, age=18, level=3]
Person [name=老六, age=20, level=3]
Person [name=李四, age=24, level=4]
注意:这一种方式相较于其他的方式有什么优点,它能够针于对同样的一组数据,做不同的处理,什么意思呢,就是那么我的需求发生了变化,我要按照这个字母的方式去对比,那么我可以根据不同的需求只要改正一个地方就可以了,假如说:我的A模块要按照名字或者等级排序那么就只要写上面的代码就可以了,那么在另外一个地方就要看下面的代码块了。
四.set集合比较器排序
这些数据假如不来于你的数据库,来自别人的
set.add(new Person("zs", 18, 1));
set.add(new Person("ls", 24, 4));
set.add(new Person("ww", 26, 2));
set.add(new Person("laoliu", 20, 3));
set.add(new Person("bajie", 18, 3));
有一个菜单,用户管理、会议管理、档案管理。如果想实现这些需求
代码块,就只需要这样就可以了
TreeSet<Person> set = new TreeSet<>((x,y)-> x.getName().compareTo(y.getName()));
按照名字的排序结果:
Person [name=bajie, age=18, level=3]
Person [name=laoliu, age=20, level=3]
Person [name=ls, age=24, level=4]
Person [name=ww, age=26, level=2]
Person [name=zs, age=18, level=1]
代码块:
TreeSet<Person> set = new TreeSet<>((x,y)-> x.getAge() - y.getAge());
按照年龄排序结果:这里有少了一个怎么解决呢?
Person [name=zs, age=18, level=1]
Person [name=laoliu, age=20, level=3]
Person [name=ls, age=24, level=4]
Person [name=ww, age=26, level=2]
解决方法:
TreeSet<Person> set = new TreeSet<>((x,y)-> {
int ageRes = x.getAge() - y.getAge();
int leveRes = 0;
if(ageRes == 0) {
leveRes = x.getLevel() - y.getLevel();
}
else {
return ageRes;
}
return leveRes;
});
正确的结果:
Person [name=zs, age=18, level=1]
Person [name=bajie, age=18, level=3]
Person [name=laoliu, age=20, level=3]
Person [name=ls, age=24, level=4]
Person [name=ww, age=26, level=2]
只要改代码就可以了,不会写s的,不管你的需求怎么变,我们的可以进行有效的处理。这就是比较序排序