Java 数据类型:集合接口Collection之Set接口HashSet类;LinkedHashSet;TreeSet 类
Collection 之 Set
实现类:
- HashSet
- TreeSet
特点:
- 无序。
- 元素不可重复。
(如果试图添加一个已经有的元素到一个Set集合中,那么会添失败,add()方法返回false,且新元素不会被加入)
HashSet:
- 元素的值可以是null。
- HashSet是不同步的,如果有多个线程访问一个HashSet我们必须通过代码来保证同步?
底层架构:
- 底层是HashMap;
- HashSet 就是HashMap键的集合
HashSet<String > hashSet = new HashSet<>(); /* * HashSet底层是HashMap */ //源码HahsSet的构造方法: public HashSet() { map = new HashMap<>(); }
import java.util.Collection; import java.util.HashSet; import java.util.Set; /** * @ClassName HashSetExample * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/4/9. */ public class HashSetExample { public static void main(String[] args) { Set persons = new HashSet(); persons.add("张三"); persons.add("李四"); persons.add("王五"); System.out.println(persons); //[李四, 张三, 王五] } }
hashSet添加元素流程解析:
- hashCode不同,不再调用equals判断元素是否相同。
- hashCode相等,但是equals返回的是false,那么我们会在相同的位置添加两个元素(通过链表的方法存储)。
- hashCode相等,equals返回也为true,不存储。
注意了,一般在开发的时候,为了判断两个元素是否相等,我们需要重写equals和hashCode,并且要保证equals和hashCode的一致性,如果equals返回为true,那么他们的hashCode应该要相等
示例代码:
import java.io.PrintStream; import java.util.HashSet; import java.util.Objects; import java.util.Set; /** * @ClassName Hash * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/4/9. */ public class HashSetDecideEqualsExample { public static class User{ private String name; public User(String name) { this.name = name; } @Override public boolean equals(Object o) { System.out.println("调用equals"); // if (this == o) return true; // if (o == null || getClass() != o.getClass()) return false; // User user = (User) o; // return Objects.equals(name, user.name); return true; } @Override public int hashCode() { System.out.println("调用hashCode"); return Objects.hash(name); // return 1; } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } } public static void main(String[] args) { Set persons = new HashSet(); persons.add(new User("张三")); persons.add(new User("李四")); persons.add(new User("张三")); persons.add(new User("王五")); System.out.println(persons); } } /** * 输出如下:User张三hashCode相同,然后调用了equals,判断是否相同,仍相同,第二个张三User未添加 调用hashCode 调用hashCode 调用hashCode 调用equals 调用hashCode [User{name='李四'}, User{name='张三'}, User{name='王五'}] */
LinkedHashSet:
- LinkedHashSet是HashSet的一个子类,LinkedHashSet集合也是根据元素的hashCode值来决定元素的存储位置
- 有序:它使用链表维护元素的次序,这样使得元素看起来是以插入顺序保存的。当遍历LinkedHashSet集合里面的元素时,LinkedHashSet将会按照元素的添加顺序来访问集合里的元素。
- 性能:略低于HashSet的性能,但迭代访问Set里面的元素的时候新能会更好,因为用链表维护了内部的顺序。
import java.util.LinkedHashSet; public class LinkHashSetExample { public static void main(String[] args) { LinkedHashSet linkedHashSet = new LinkedHashSet(); linkedHashSet.add("d"); linkedHashSet.add("a"); linkedHashSet.add("c"); linkedHashSet.add(3); linkedHashSet.add(2); linkedHashSet.add(8); System.out.println(linkedHashSet);//[d, a, c, 3, 2, 8] } }
TreeSet 类
特点:添加元素时自动排序
- 向TreeSet集合中添加元素就是吧元素作为键添加到底层的TreeMap中;
- TreeSet 就是TreeMap键的集合
- SortedSet:接口要求集合中元素必须是可比较的(要求元素的类实现Comparator接口)
与HashSet集合相比,TreeSet还提供了以下几个额外的方法:
- Comparator comparator():如果TreeSet采用了定制排序,则该方法返回定制排序所使用的Comparator,如果采用TreeSet自然排序,那么返回null。
- Object first():返回集合中第一个元素
- Object last():返回集合中的最后一个元素
- Object lower(Object e):返回集合中指定位于指定元素之前的元素。
- Object higher(Object e):返回集合中位于指定元素之后的元素。
- SortedSet subSet(Object fromElement, Object toElement): 返回此Set的子集合,范围从fromElement(包含)到toElement(不包含)。
- SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成。
- SortedSet tailSet(Object fromElement):返回此Set的子集,由大于或者等于fromElement的元素组成。
【排序逻辑】
-
TreeSet中,判断是否同一个元素,根据Comparator/Comparable的比较结果返回是否为0,如果比较结果为0 认为是相同元素。
-
在使用treeSet时,既可以在构造方法中指定Comparator类的匿名对象,也可以让元素的类实现Comparable接口。对TreeSet来说,他是先选择的Comparator,没有Comparator再选择Comparable。
- 对于程序员来说,实现Comparable接口重写CompareTo方法进行排序,或者做相等判断。一般定义一个比较广泛的比较规则。可以通过在构造方法中指定Comparator定义各种不同的比较规则
自定义添加元素排序逻辑
场景1、在TreeSet构造方法中指定Comparator比较器.-->示例代码设置逆序排序
public class TreeSetTest { public static void main(String[] args) { TreeSet<String> treeSet = new TreeSet<>(new Comparator<String>() { @Override public int compare(String o1, String o2) { return o2.compareTo(o1); } }); treeSet.add("c"); treeSet.add("b"); treeSet.add("d"); treeSet.add("a"); System.out.println(treeSet);//[d, c, b, a] } }
import java.util.Comparator; import java.util.TreeSet; /** * @ClassName TreeSetSortExample * @projectName: object1 * @author: Zhangmingda * @description: * date: 2021/4/10. */ public class TreeSetSortExample { public static class User { int age; public User(int age) { this.age = age; } @Override public String toString() { return "User{" + "age=" + age + '}'; } public static void main(String[] args) { //创建TreeSet时自定义排序方法 // TreeSet<User> users1 = new TreeSet<>(new Comparator<User>() { // @Override // public int compare(User user, User t1) { // return t1.age - user.age; //逆序 // } // }); TreeSet<User> users1 = new TreeSet<>((User u1,User u2) ->{return u2.age - u1.age;});//逆序 users1.add(user1); users1.add(user); users1.add(user2); users1.add(user3); System.out.println(users1); //[User{age=88}, User{age=7}, User{age=2}, User{age=-8}] } }
场景2、要求自定义元素的类实现Comparator接口
import java.util.TreeSet; /** * @ClassName TreeSetSortExample * @projectName: object1 * @author: Zhangmingda * @description: XXX * date: 2021/4/10. */ public class TreeSetSortExample { public static class User implements Comparable { int age; public User(int age) { this.age = age; } @Override public String toString() { return "User{" + "age=" + age + '}'; } @Override public int compareTo(Object o) { User user = (User) o; return this.age - user.age; } } public static void main(String[] args) { TreeSet<User> users = new TreeSet<>(); User user = new User(2); User user1 = new User(7); User user2 = new User(88); User user3 = new User(-8); users.add(user1); users.add(user); users.add(user2); users.add(user3); System.out.println(users); //[User{age=-8}, User{age=2}, User{age=7}, User{age=88}] } }
EnumSet:
- EnumSet allOf(Class elementType): 创建一个包含指定枚举类里所有枚举值的EnumSet集合。
- EnumSet complementOf(EnumSet e): 创建一个其元素类型与指定EnumSet里元素类型相同的EnumSet集合,新EnumSet集合包含原EnumSet集合所不包含的、此类枚举类剩下的枚举值(即新EnumSet集合和原EnumSet集合的集合元素加起来是该枚举类的所有枚举值)。
- EnumSet copyOf(Collection c): 使用一个普通集合来创建EnumSet集合。
- EnumSet copyOf(EnumSet e): 创建一个指定EnumSet具有相同元素类型、相同集合元素的EnumSet集合。
- EnumSet noneOf(Class elementType): 创建一个元素类型为指定枚举类型的空EnumSet。
- EnumSet of(E first,E…rest): 创建一个包含一个或多个枚举值的EnumSet集合,传入的多个枚举值必须属于同一个枚举类。
- EnumSet range(E from,E to): 创建一个包含从from枚举值到to枚举值范围内所有枚举值的EnumSet集合。
import java.util.EnumSet; public class EnumSetTest { private static enum Season { SPRINT, SUMMER, FALL, WINTER } public static void main(String[] args) { EnumSet es1 = EnumSet.allOf(Season.class); System.out.println(es1); EnumSet es2 = EnumSet.noneOf(Season.class); System.out.println(es2); es2.add(Season.SUMMER); es2.add(Season.FALL); System.out.println(es2); } }
Set性能分析:
public class TreeSetTest02 {
public static void main(String[] args) {
//定义一个TreeSet集合存储Person,在TreeSet构造方法中指定Comparator比较器,根据年龄降序排序
TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person o1, Person o2) {
return o2.getAge() - o1.getAge();
}
});
treeSet.add(new Person("zhangsan",20));
treeSet.add(new Person("lisi",23));
treeSet.add(new Person("wangwu",14));
treeSet.add(new Person("zhaoliu",35));
treeSet.add(new Person("tiaoqi",57));
System.out.println(treeSet.contains(new Person("Shabi",14)));//true
//这里根据Comparator比较器返回 0 即认为是同一个元素
TreeSet<Person> treeSet1 = new TreeSet<>();
//如果没有在构造方法指定Comparator比较器,要求元素的类实现Comparator接口
treeSet1.add(new Person("zhangsan",20));
treeSet1.add(new Person("lisi",23));
treeSet1.add(new Person("wangwu",14));
treeSet1.add(new Person("zhaoliu",35));
treeSet1.add(new Person("tiaoqi",57));
System.out.println(treeSet1.contains(new Person("Shabi",14)));//false
System.out.println(treeSet1);
}
}
//Person类实现Comparable接口,通过Comparable<Person>泛型指定比较元素的数据类型也是Persion
class Person implements Comparable<Person> {
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return age == person.age &&
Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", 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 int compareTo(Person o) {
if (this.age == o.getAge() && this.name == o.getName()){
return 0;}
else
return this.name.compareTo(o.getName());
//集合中存储多个对象的时候,根据返回值是否是0判断是否是同一个对象
}
}
posted on 2021-04-09 13:27 zhangmingda 阅读(152) 评论(0) 编辑 收藏 举报