Set集合介绍
Set简介
Collection集合体系
Collection接口,其子接口有List、Set接口
Set集合其实就是一个接口,HashSet和TreeSet实现了Set接口,所有Set所具备的方法HashSet和TreeSet也是具备的。
Set接口实现类:HashSet 、TreeSet
Set增删改查
实例化 : Set s = new HashSet();
增
//增加单个元素 s.add("a"); //增加集合 s.addAll(new ArrayList(30));
删
//删除单个元素 remove("a"); //删除一个集合 removeAll(new ArrayList(30));
改
说明:Set集合因为是无序,没有自带的更改方法,但是我们可以根据自己需求组合查,删,增,的方法自己写出一个改(看自己领悟能力)。
查
//根据元素查找 s.contains("a"); //查看集合长度 s.size();
Set集合无序存储的原因
Set集合的底层实现实际上时采用哈希表存储元素
JDK1.8之前:哈希表 = 数组 + 链表 + ( 哈希算法 )
JDK1.8之后:哈希表 = 数组 + 链表 + 红黑树 + ( 哈希算法 )
当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
一、Set集合特点
1.不可重复加入元素对象
由以下代码可证明
package com.SAME_LOVE; import java.util.HashSet; import java.util.Set; public class Demo01 { public static void main(String[] args) { Set s = new HashSet(); s.add("丘比特"); s.add("马德论"); s.add("丘比特"); s.add("马德论"); s.add("萨斯利"); System.out.println(s); } }
输出结果为:
2.无序输出
package com.SAME_LOVE; import java.util.HashSet; import java.util.Set; public class Demo01 { public static void main(String[] args) { //实例化集合 Set s = new HashSet(); //增加元素对象 s.add(new Person(1, "丘比特",22)); s.add(new Person(2, "马德论",19)); s.add(new Person(3, "萨斯利",25)); s.add(new Person(4, "萨斯利",18)); //循环遍历 for (Object obj: s) { System.out.println(obj); } } } class Person{ private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } 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() { super(); } public Person(int id, String name, int age) { super(); this.id = id; this.name = name; this.age = age; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
以上代码执行结果为 如图:
二、Set遍历
foreach
//实例化集合 Set s = new HashSet(); //增加元素对象 s.add("丘比特"); s.add("马德论"); s.add("萨斯利"); for (Object obj: s) { System.out.println(obj); }
输出结果如下: 马德论 萨斯利 丘比特
迭代器
package com.SAME_LOVE; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class Demo01 { public static void main(String[] args) { //实例化集合 Set s = new HashSet(); //增加元素对象 s.add(new Person(1, "丘比特",22)); s.add(new Person(2, "马德论",19)); s.add(new Person(3, "萨斯利",25)); s.add(new Person(4, "萨斯利",18)); //循环遍历 Iterator it = s.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } class Person{ private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } 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() { super(); } public Person(int id, String name, int age) { super(); this.id = id; this.name = name; this.age = age; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", age=" + age + "]"; } }
三、HashSet去重原理
代码测试
package com.SAME_LOVE; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class Demo01 { public static void main(String[] args) { //实例化集合 Set s = new HashSet(); //增加元素对象 s.add(new Person(1, "丘比特",22)); s.add(new Person(2, "马德论",19)); s.add(new Person(2, "马德论",19)); s.add(new Person(3, "萨斯利",25)); s.add(new Person(4, "萨斯利",18)); s.add(new Person(4, "萨斯利",18)); //循环遍历 Iterator it = s.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } class Person{ private int id; private String name; private int age; public int getId() { return id; } public void setId(int id) { this.id = id; } 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() { super(); } public Person(int id, String name, int age) { super(); this.id = id; this.name = name; this.age = age; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + id; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { 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 (id != other.id) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; } }
输出结果
如图:
由以上代码测试得出:
最终原理(结论)
- HashSet去重是有元素对象的hashCode方法和equals方法的返回值决定的
- 先会调用hashCode方法判断元素对象的属性如果返回值一致说明该集合里面已有该元素对象不能继续增加
- 如果hashCode方法返回值不一样将调用equals方法进行内容判断有重复已将不能进行增加
- 在此之前两个方法都必须重写,不然不能进行去重
- 就算重写hashCode方法和equals方法如果想不进行去重,将hashCode方法返回值定为始终返回一样的值即可
四、TreeSet 自然排序.比较器排序
1.自然排序
提示:进行自然排序操作该对象必须实现java.lang.Comparable接口并且重写compareTo方法,否则会报此异常错误
Exception in thread "main" java.lang.ClassCastException:
com.SAME_LOVE.Person cannot be cast to java.lang.Comparable
代码测试:
package com.SAME_LOVE; import java.util.HashSet; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; public class Demo01 { public static void main(String[] args) { //实例化集合 HashSet s = new HashSet(); //增加元素对象 s.add(new Person(1, "丘比特",22,11000)); s.add(new Person(2, "马德论",19,24000)); s.add(new Person(3, "卡卡西",19,15000)); s.add(new Person(4, "Ikun",25,20000)); s.add(new Person(5, "小黑子",18,2100)); s.add(new Person(6, "萨斯利",18,9000)); //循环遍历 Iterator it = s.iterator(); System.out.println("没有排序之前的顺序"); while (it.hasNext()) { System.out.println(it.next()); } //实例化集合 TreeSet st = new TreeSet(); //遍历HashSet集合 for (Object object : s) { //加入TreeSet集合之前会调用对象重写的compare方法进行排序 st.add(object); } System.out.println("已经排序之后的顺序"); for (Object obj : st) { System.out.println(obj); } } } class Person implements Comparable<Person>{ private int id; private String name; private int age; private int money; public int getId() { return id; } public void setId(int id) { this.id = id; } 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 int getMoney() { return money; } public void setMoney(int money) { this.money = money; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", age=" + age + ", money=" + money + "]"; } public Person(int id, String name, int age, int money) { super(); this.id = id; this.name = name; this.age = age; this.money = money; } public Person() { super(); } @Override public int compareTo(Person o) { return this.id - o.id; } }
以上代码执行的输出结果为:
测试得出其原理:
- 如果想对元素对象其他属性进行排序,修改compareTo方法的返回值即可
- this比较元素对象是进行升序
- 元素对象比较this的进行降序
2.构造器使用排序(比较器排序)
提示:进行比较器排序操作该对象必须实现java.lang.Comparable接口,TreeSet在实现java.util.Comparator的匿名内部类并且重写compare方法,否则会报错
代码测试:
package com.SAME_LOVE; import java.util.Comparator; import java.util.Iterator; import java.util.TreeSet; public class Demo01 { public static void main(String[] args) { //实例化集合 TreeSet s = new TreeSet(); //增加元素对象 s.add(new Person(1, "丘比特",22,11000)); s.add(new Person(2, "马德论",19,20000)); s.add(new Person(3, "卡卡西",25,20000)); s.add(new Person(4, "Ikun",22,20000)); s.add(new Person(5, "小黑子",25,9000)); s.add(new Person(6, "萨斯利",18,9000)); //循环遍历 Iterator it = s.iterator(); System.out.println("没有进行比较器排序之前的顺序"); while (it.hasNext()) { System.out.println(it.next()); } //实例化集合 TreeSet st = new TreeSet<>(new Comparator<Person>() { //需求:在比较Money一样的同时再比较Age进行降序 @Override public int compare(Person o1, Person o2) { //Money进行比较降序 int last = o2.getMoney() - o1.getMoney(); //判断Money比较后对于0 if(last == 0) { //在进行Age降序 return o2.getAge() - o1.getAge(); } return last; } }); //遍历HashSet集合 for (Object object : s) { //加入TreeSet集合之前会调用对象重写的compare方法进行排序 st.add(object); } System.out.println("已经进行比较器排序之后的顺序"); for (Object obj : st) { System.out.println(obj); } } } class Person implements Comparable<Person>{ private int id; private String name; private int age; private int money; public int getId() { return id; } public void setId(int id) { this.id = id; } 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 int getMoney() { return money; } public void setMoney(int money) { this.money = money; } @Override public String toString() { return "Person [id=" + id + ", name=" + name + ", age=" + age + ", money=" + money + "]"; } public Person(int id, String name, int age, int money) { super(); this.id = id; this.name = name; this.age = age; this.money = money; } public Person() { super(); } @Override public int compareTo(Person o) { return this.id - o.id; } }
以上代码输出结果为:
由以上测试得出其原理:
- 先在TreeSet集合内部实现java.util.Comparator的匿名内部类并且重写compare方法
- 比较器可以对元素对象的属性进行多次比较后进行排序---升序和降序都可
- 根据所需要求想如何排序修改对比集合中的元素属性即可(本测试要求为:先按Money进行降序,当Money对比返回值一样的同时进行Age就降序【如上一图所示】);
- 想要修改为升序,将compare方法第一个对象参数放在前面对比
- 想要修改为降序,则将compare方法第一个对象参数放后面对比