1.Set集合的特点
1.1无序
就是数据添加的顺序和取出的顺序是不一致的
Set<Integer> set=new HashSet<Integer>(); set.add(1); set.add(4); set.add(2); set.add(8); set.forEach(System.out::println);
数据是不一样的,但是已经排序好了(升序)
1.2唯一
很好理解,就是唯一的是不可以添加重复的数据,否则会被覆盖
Set<Integer> set =new HashSet<Integer>(); set.add(1); set.add(9); set.add(7); set.add(8); set.add(8); set.forEach(System.out::println);
不仅仅已经排好序了,还把重复的数字8给覆盖了
但是数字不能直观的理解到,那我们就用数组来看一下
首先把User对象创建一下(先不要写tostring方法)
Set<User> set=new HashSet<User>();
set.add(new User(1,"zs","123"));
set.add(new User(2,"ls","123"));
set.add(new User(1,"zs","13"));
for (User user : set) {
System.out.println(user);
}
用数组的换,就是可以看到,zs并没有被消除掉
而且输出的格式:类的全路径名+@+十六进制内存地址
问题原因:判断重复元素的时候,Set集合会调用hashCode()和equal()方法来实现;而在没有重写equals方法之前默认比较的是Object(引用类型),实际上比较的是内存地址。
所以我们要重写User对象中的equals方法,比较User对象中的属性。
到User里右键点击生成
点击红色框框标记的地方
到了这里就要注意了,他这里默认的是最后一个,我们要选中第一个,也就是红色框框标记的,然后就点击下一步,后面出来的,都是点击下一步就可以了,就不用管他了
像这样给他们改一下,然后把tostring方法写上,运行看一下效果
@Override
public boolean equals(Object o) {
//this是当前user对象
//当前对象是否与传入的user对象相同
if (this == o) return true;
//传入的对象是null或者当前的对象的类对象不同于传入
// 的user对象的类对象
if (o == null || getClass() != o.getClass()) return false;
//将O强制转换为String
User user = (User) o;
// if (id != user.id) return false;
// if (!Objects.equals(uname, user.uname)) return false;
// return Objects.equals(pwd, user.pwd);
// 判断当前User姓名与传入的user姓名是否相同
// true:存在相同的
// false:反之
if (uname.equals(user.uname)){
return true;
}else {
return false;
}
}
@Override
public int hashCode() {
int result = id;
result = 31 * result + (uname != null ? uname.hashCode() : 0);
// result = 31 * result + (pwd != null ? pwd.hashCode() : 0);
return result;
}
先比较hashcode方法,然后在比较equals方法
如果hashcode方法返回值相同,再比较equals方法的结果
如果hashcode方法返回值不相同 ,equals就不比较
不比较就是新对象,就允许添加
运行后是被覆盖了,还是过滤了.输出的密码为123 被过滤了,要是为13,就是被覆盖了
2.Set的遍历方式
2.1 foreach循环
Set<String> set=new HashSet<String>(); set.add("zs"); set.add("ls"); set.add("ww"); for(String str:set){ System.out.println(str); }
2.2 迭代器循环
Set<String> set=new HashSet<String>(); set.add("zs"); set.add("ls"); set.add("ww"); Iterator<String> iterator = set.iterator(); while (iterator.hasNext()){ System.out.println(iterator.next()); }
两种循环运行出来的效果都是一样的,运行出来的数据就跟我们所写的数据是不一样的,是按照字母排序的
3.TreeSet
TreeSet:安照某种特定的规则对集合中的元素进行排序(升序和降序)
是一个有序的集合,它的作用是提供有序的Set集合。TreeSet是基于TreeMap实现的。
TreeSet中的元素支持2种排序方式:自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序。
3.1 java.lang.Comparable:自然比较接口
在User中实现(implements) Comparable<User>
重写
@Override public int compareTo(User o) { return this.id-o.id;//升序 // return -(this.id-o.id);//降序 //这个方法也是升序的 // if (this.id>o.id){ // return 1; // }else { // if (this.id==o.id){ // return 0; // }else { // return -1; // } // } }
Set<User> set=new TreeSet<>(); set.add(new User(2,"zs","321")); set.add(new User(4,"bs","321")); set.add(new User(1,"hs","321")); set.add(new User(3,"ls","321")); set.forEach(System.out::println);
运行后的代码是
上面id不是按照顺序写的,都是运行后就自动的分好了
3.2 java.util.Comparator:比较器
重新创建 NameComparator 类
实现 Comparator<User>
重写方法
package com.zking.text;
import com.zking.entyti.User;
import java.util.Comparator;
public class NameComparator implements Comparator<User> {
@Override
public int compare(User a, User b) {
return b.getUname().hashCode()-a.getUname().hashCode();
}
}
Set<User> set=new TreeSet<>(new NameComparator());
set.add(new User(2,"zs","321"));
set.add(new User(4,"bs","321"));
set.add(new User(1,"hs","321"));
set.add(new User(3,"ls","321"));
set.forEach(System.out::println);
运行这串代码
发现他不是按照id排序了,他是按照字母排序(降序)的
那就有人问了,为什么是降序呢,不是升序,简单
@Override
public int compare(User a, User b) {
return -(b.getUname().hashCode()-a.getUname().hashCode());
}
像这样子,是不是就升序了
好啦,完成啦ヾ(≧▽≦*)o