前言:给大家讲讲Set结合框架
码字不易,点个关注
转载请说明!
思维导图:
目录
1.List和Set的区别
List , Set 都是继承自Collection 接口
1.两者的特点
List 特点:一个有序(元素存入集合的顺序和取出的顺序一致)容器,元素可以重复,可以插入多个null元素,元素都有索引。常用的实现类有 ArrayList、LinkedList 和 Vector
Set 特点:一个无序(存入和取出顺序有可能不一致)容器,不可以存储重复元素,只允许存入一个null元素,必须保证元素唯一性。Set 接口常用实现类是 HashSet、LinkedHashSet 以及 TreeSet
2.两者之间的对比
List:和数组类似,List可以动态增长,查找元素效率高,插入删除元素效率低,因为会引起其他元素位置改变
Set:检索元素效率低下,删除和插入效率高,插入和删除不会引起元素位置改变
3.取值
List 支持for循环,也就是通过下标来遍历,也可以用迭代器(到这里大家可能会好奇foreach怎么不是,因为foreach本质上也是迭代器)
Set只能用迭代,因为他无序,无法用下标来取得想要的值
2.Set集合的特点
1.无序
2.不可重复
3.Set集合的循环方式
1.foreach遍历
2.迭代器
代码展示:
/**
* 特点: 1.不可重复 2.无序
*
* @author zjjt
*
*/
public class Dome1 {
public static void main(String[] args) {
Set<Object> set = new HashSet<>();
set.add("a");
set.add("b");
set.add("c");
set.add("b");
/**
* foreach遍历
*/
for (Object h : set) {
System.out.println(h);
}
System.out.println("-------------");
/**
* Iterator(迭代器)
*/
Iterator<Object> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
输出结果如下:
4.HashSet去重复以及原理
1.去重复的原理
向HashSet 中add ()元素时,判断元素是否存在的依据,不仅要比较hash值,同时还要结合equles 方法比较
*HashSet 中的add ()方法会使用HashMap 的put()方法
Hashset底层数据结构:Hash表
优先会调用hashcade()方法对比地址,然后调用equals()方法对比值
Set集合加的是地址,不允许添加重复的地址
Set集合去重其实是去重一个相同的地址
2.hashCode()与equals()的相关规定:
1.如果两个对象相等,则hashcode一定也是相同的
2.两个对象相等,对两个equals方法返回true
3.两个对象有相同的hashcode值,它们也不一定是相等的
4.综上,equals方法被覆盖过,则hashCode方法也必须被覆盖
5.hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
3.==与equals的区别
1.==是判断两个变量或实例是不是指向同一个内存空间 equals是判断两个变量或实例所指向的内存空间的值是不是相同
2.==是指对内存地址进行比较 equals()是对字符串的内容进行比较3.==指引用是否相同 equals()指的是值是否相同
代码展示:
public class Dome2 {
public static void main(String[] args) {
Set<Object> set=new HashSet<>();
set.add(new people("张三", 20));
set.add(new people("李四", 22));
set.add(new people("王五", 24));
set.add(new people("赵六", 26));
set.add(new people("李四", 22));
for (Object h : set) {
System.out.println(h);
}
}
}
class people {
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;
}
@Override
public String toString() {
return "people [name=" + name + ", age=" + age + "]";
}
public people(String name, int age) {
super();
this.name = name;
this.age = age;
}
}
输出结果如下:
地址的一个生成规则:
1.new一个对象生成一个新的地址
怎么去实现去重?
只要去重同一个地址即可,在people类调用hashcade() and equals()方法
Hashset底层数据结构:Hash表
优先会调用hashcade()方法对比地址,然后调用equals()方法对比值
代码展示:
/**
* Set集合去重
* Hashset底层数据结构:Hash表
* 优先会调用hashcade()方法对比地址,然后调用equals()方法对比值
*
*/
public class Dome2 {
public static void main(String[] args) {
Set<Object> set=new HashSet<>();
set.add(new people("张三", 20));
set.add(new people("李四", 22));
set.add(new people("王五", 24));
set.add(new people("赵六", 26));
set.add(new people("李四", 22));
for (Object h : set) {
System.out.println(h);
}
}
}
class people {
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;
}
@Override
public String toString() {
return "people [name=" + name + ", age=" + age + "]";
}
public people(String name, int age) {
super();
this.name = name;
this.age = age;
}
@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;
people other = (people) 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;
}
}
输出结果如下:
5.TreeSet底层实现和原理
本人使用的是jdk1.8版本
TreeSet实现了SortedSet接口,它是一个有序的集合类,TreeSet的底层是通过TreeMap实现的。TreeSet并不是根据插入的顺序来排序,而是根据实际的值的大小来排序。TreeSet也支持两种排序方式:
- 自然排序
- 比较器排序(自定义排序)
- 排序的意义在哪里?
假如你和第三方进行一个数据的交互的时候,对方没有做排序
我们用这个排序(自然排序,自定义排序)去自动排序,脱离数据脚本(sql语句)进行排序
1.自然排序
特点:写死了排序规则,每一个模块都按照这个规则走,不灵活
代码展示:
/**
* 自然排序
* @author zjjt
*
*/
public class Dome3 {
public static void main(String[] args) {
Set<User> set=new TreeSet<>();
set.add(new User("张三", 20000));
set.add(new User("李四", 13000));
set.add(new User("王五", 12500));
set.add(new User("赵六", 18000));
for (User h : set) {
System.out.println(h);
}
}
}
class User{
private String name;
private int money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public String toString() {
return "User [name=" + name + ", money=" + money + "]";
}
public User(String name, int money) {
super();
this.name = name;
this.money = money;
}
}
这里执行会报错的!!!
原因:因为User类没有实现自然排序接口
解决方法:实现自然排序接口并重写方法
/**
* 自然排序
* 不方便
* 把自然排序的接口绑定在了User对象上意味着没办法去做更改
*
*/
public class Dome3 {
public static void main(String[] args) {
Set<User> set=new TreeSet<>();
set.add(new User("张三", 20000));
set.add(new User("李四", 13000));
set.add(new User("王五", 12500));
set.add(new User("赵六", 18000));
//com.hpw_set.User cannot be cast to java.lang.Comparable 类型转换异常
for (User h : set) {
System.out.println(h);
}
}
}
class User implements Comparable{//实现了自然排序接口
private String name;
private int money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public String toString() {
return "User [name=" + name + ", money=" + money + "]";
}
public User(String name, int money) {
super();
this.name = name;
this.money = money;
}
@Override
public int compareTo(Object o) {
User u=(User) o;
return this.money-u.money; //升序
//return u.money - this.money;降序
}
}
输出结果如下(根据money升序输出):
2.比较器排序(自定义排序)
特点:能解决不同的模块有不同的排序规则,你在哪个模块想要哪个排序规则都可以进行定义,修改
代码如下:
/**
* 比较器排序
* 能解决不同的模块有不同的排序规则
* 你在哪个模块想要哪个排序规则都可以进行定义,修改
*
*/
public class Dome4 {
public static void main(String[] args) {
Set<User2> set=new TreeSet<>(new Comparator<User2>() {
@Override
public int compare(User2 o1, User2 o2) {
return -(o1.getMoney()-o2.getMoney());//Money降序
}
});
set.add(new User2("张三", 20000));
set.add(new User2("李四", 13000));
set.add(new User2("王五", 12500));
set.add(new User2("赵六", 18000));
for (User2 h : set) {
System.out.println(h);
}
}
}
class User2 {
private String name;
private int money;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getMoney() {
return money;
}
public void setMoney(int money) {
this.money = money;
}
@Override
public String toString() {
return "User2 [name=" + name + ", money=" + money + "]";
}
public User2(String name, int money) {
super();
this.name = name;
this.money = money;
}
}
输出结果如下 (根据money降序输出):
到这里就结束了,我依旧是那个学IT的小学生
欢迎大佬指点