Set集合
特点
- Set集合中的元素是唯一的,不可重复(取决于hashCode和equals方法),也就是说具有唯一性。
- Set集合中元素不保证存取顺序,并不存在索引。
继承关系
Collection
|--Set:元素唯一,不保证存取顺序,只可以用迭代器获取元素。
|--HashSet:哈希表结构,非线程安全,查询速度较快。元素唯一性取决于hashCode和equals方法。
|--LinkedHashSet:带有双向链表的哈希表结构,非线程安全,保持存取顺序,保持了查询速度较快特点。
|--TreeSet:平衡排序二叉树(红黑树)结构,非线程安全,按自然排序或比较器存入元素以保证元素有序。
元素唯一性取决于ComparaTo方法或Comparator比较器。
|--Set:元素唯一,不保证存取顺序,只可以用迭代器获取元素。
|--HashSet:哈希表结构,非线程安全,查询速度较快。元素唯一性取决于hashCode和equals方法。
|--LinkedHashSet:带有双向链表的哈希表结构,非线程安全,保持存取顺序,保持了查询速度较快特点。
|--TreeSet:平衡排序二叉树(红黑树)结构,非线程安全,按自然排序或比较器存入元素以保证元素有序。
元素唯一性取决于ComparaTo方法或Comparator比较器。
常用方法
Set集合的方法和Collection集合的方法几乎一致。
HashSet集合
特点
- 元素具有唯一性,取决于hashCode和equals方法。
- 元素不保证存取顺序。
- 由于采用哈希表数据结构,所以查询较快。
- 与List一样,建议使用多态的方式,创建HashSet集合并使用Set接口方法。
关于hashCode和equals方法
- 在以哈希表为数据结构的容器中,其存放地址取决于hashCode方法计算的值,如果hashCode的值相同,则用equals方法判断是否相同,如果都相同则判定为相同元素。
- 在以哈希表为数据结构的容器使用过程中,已经加入的元素不可以变更hashCode方法所依赖的域的值,否则会导致元素hashCode值已变化,但是其在容器中的位置却没有变化,后果是接下来的remove等操作将因为无法找到该元素而移除失败,进一步导致内存泄露。
元素唯一性示例
Person.java
package bean;public class Person {private String name;private int age;public Person(String name, int age) {super();this.name = name;this.age = age;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic 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 (name == null) {if (other.name != null) return false;} else if (!name.equals(other.name)) return false;return true;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + "]" ;}}
HashSetDemo.java
package Collection;import java.util.HashSet;import java.util.Iterator;import java.util.Set;import bean.Person;public class HashSetDemo {public static void main(String[] args) {// Set集合保证元素唯一性。Set<String> set = new HashSet<String>();set.add("Java1");set.add("Java2");set.add("Java1");set.add("Java1");set.add("Java2");for (Iterator<String> it = set.iterator(); it.hasNext();) {System.out.println( it.next());}System.out.println( "-------------------");// Set集合存储自定义类时,建议该类重写hashCode和equals方法,这是保证元素唯一性的前提,一般还会重写toString方法。Set<Person> setObj = new HashSet<Person>();setObj.add(new Person( "Jacob", 25));setObj.add(new Person( "Meteor", 23));setObj.add(new Person( "Tom", 26));setObj.add(new Person( "Llllin", 27));setObj.add(new Person( "Jacob", 24));for (Iterator<Person> it = setObj.iterator(); it.hasNext();) {System.out.println( it.next());}}}
运行结果
Java2
Java1
-------------------
Person [name=Jacob, age=25]
Person [name=Tom, age=26]
Person [name=Jacob, age=24]
Person [name=Meteor, age=23]
Person [name=Llllin, age=27]
不保证元素存取顺序示例
package Collection;import java.util.HashSet;import java.util.Iterator;import java.util.Set;public class HashSetDemo {public static void main(String[] args) {// Set集合不保证存取顺序。Set<String> set = new HashSet<String>();set.add("Java1");set.add("Java2");set.add("Java3");set.add("Java4");set.add("Java5");for (Iterator<String> it = set.iterator(); it.hasNext();) {System. out.println(it .next());}}}
运行结果
Java2
Java3
Java4
Java5
Java1
比较器
1. Comparable接口
自定义类如果实现该接口,那么重写该接口唯一的方法comparaTo(E),可以让该类具有可比较性。
2. Comparator接口
实现该接口的类被称之为比较器,一般只具有一个方法,就是重写的这个接口的compara(E o1, E o2)方法,实现两个对象之间的比较。
案例
获取Set集合中元素的最大值(要求元素具有可比性)。
ComparatorByLength.java
package comparator;import java.util.Comparator;public class ComparatorByLength implements Comparator<String> {@Overridepublic int compare(String s1, String s2) {int result = s1.length() - s2.length();return result == 0 ? s1 .compareTo(s2 ) : result ;}}
HashSetTest.java
package collection.set;import java.util.Collections;import java.util.HashSet;import java.util.Iterator;import java.util.Set;import comparator.ComparatorByLength;public class HashSetTest {public static void main(String[] args) {/** 案例:获取集合最大值*/Set<String> set = new HashSet<String>();set.add("Jacob");set.add("Java");set.add("Meteor");set.add("abc");set.add("it&java");set.add("zz");// 方法一:使用Collections.max()方法(使用的是自然排序方法)。System.out.println(Collections. max(set));// 方法二:使用自然排序System.out.println( getMax(set));// 方法三:使用比较器(ComparatorByLength)System.out.println( getMax(set, new ComparatorByLength()));}/*** 使用比较器获取Set集合中的最大值(使用字符串长度比较器)** @param set* @param comparatorByLength* @return*/public static Object getMax(Set<String> set , ComparatorByLength comparatorByLength ) {if (comparatorByLength == null) {throw new NullPointerException();}Iterator<String> it = set.iterator();String max = it.next();while ( it.hasNext()) {String obj = it.next();if (comparatorByLength.compare( obj, max) > 0) {max = obj;}}return max;}/*** 使用自然排序获取Set集合中的最大值。** @param set* @return*/public static Object getMax(Set<String> set ) {Iterator<String> it = set.iterator();String max = it.next();while ( it.hasNext()) {String com = it.next();if (com.compareTo( max) > 0) {max = com;}}return max;}}
运行结果
zz
zz
it&java
LinkedHashSet集合
特点
- HashSet集合具有的优点LinkedHashSet集合都具有。
- LinkedHashSet集合在HashSet查询速度快的前提下,能够保持元素存取顺序。
保持元素存取示例
package collection;import java.util.HashSet;import java.util.Iterator;import java.util.LinkedHashSet;import java.util.Set;public class Set_LinkedHashSet {public static void main(String[] args) {/** LinkedHashSet可以保持元素存取顺序*/Set<String> set1 = new HashSet<String>();Set<String> set2 = new LinkedHashSet<String>();init(set1 );init(set2 );System.out.println( "HashSet:");for (Iterator<String> it = set1.iterator(); it.hasNext();) {System.out.println( it.next());}System.out.println( "LinkedHashSet:");for (Iterator<String> it = set2.iterator(); it.hasNext();) {System.out.println( it.next());}}public static void init(Set<String> set) {set.add("Java1");set.add("Java2");set.add("Java3");set.add("Java4");set.add("Java5");}}
运行结果
HashSet:
Java2
Java3
Java4
Java5
Java1
LinkedHashSet:
Java1
Java2
Java3
Java4
Java5
TreeSet集合
特点
- 元素具有唯一性,取决于Comparable.comparaTo方法或比较器Comparator。
- 元素不保证存取顺序。
- 由于采用平衡排序二叉树,所以保存的元素均有序。
- 与List一样,建议使用多态的方式,创建TreeSet集合并使用Set接口方法。
- 创建TreeSet集合时,必须保证元素已经实现Comparable接口或者传入比较器Comparator。
示例
使用自然排序和比较器加入TreeSet集合进行排序
Person.java
package bean;public class Person implements Comparable<Person> {private String name;private int age;public Person(String name, int age) {super();this.name = name;this.age = age;}public Person() {super();}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;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic 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 (name == null) {if (other.name != null) return false;} else if (!name.equals(other.name)) return false;return true;}@Overridepublic String toString() {return "Person [name=" + name + ", age=" + age + "]" ;}@Overridepublic int compareTo(Person o) {int margin = this.name.compareTo( o. name);return margin == 0 ? this. age - o. age : margin;}}ComparatorByAge.javapackage comparator;import java.util.Comparator;import bean.Person;public class ComparatorByAge implements Comparator<Person> {@Overridepublic int compare(Person o1, Person o2) {int margin = o1.getAge() - o2.getAge();return margin == 0 ? o1 .compareTo(o2 ) : margin ;}}
TreeSetDemo.java
package collection.set;import java.util.Collections;import java.util.Iterator;import java.util.Set;import java.util.TreeSet;import bean.Person;import comparator.ComparatorByAge;import comparator.ComparatorByLength;public class TreeSetDemo {public static void main(String[] args) {// 使用自然排序将字符串加入TreeSet集合System.out.println( "字符串(自然排序):" );Set<String> set = new TreeSet<String>();set.add("java");set.add("linkedhashset");set.add("awesome");set.add("zzz");set.add("treeset");// 元素在添加的时候就已经间接调用compareTo方法进行排序for (Object object : set) {System.out.println( object);}// 使用比较器将字符串按由长至短加入TreeSet集合System.out.println( "字符串(比较器):" );Set<String> setComparatorByLength =new TreeSet<String>(Collections. reverseOrder(new ComparatorByLength()));setComparatorByLength.add( "java");setComparatorByLength.add( "linkedhashset");setComparatorByLength.add( "awesome");setComparatorByLength.add( "zzz");setComparatorByLength.add( "treeset");for (String string : setComparatorByLength) {System.out.println( string);}// 使用自然排序将自定义类加入TreeSet集合System.out.println( "自定义类(自然排序):" );Set<Person> setObj = new TreeSet<Person>();setObj.add(new Person( "jacob", 25));setObj.add(new Person( "meteor", 23));setObj.add(new Person( "kitty", 22));setObj.add(new Person( "tom", 26));for (Iterator<Person> it = setObj.iterator(); it.hasNext();) {System.out.println( it.next());}// 使用比较器将自定义类加入TreeSet集合System.out.println( "自定义类(比较器):" );TreeSet<Person> setObjComparatorByAge = new TreeSet<Person>(new ComparatorByAge());setObjComparatorByAge.add( new Person( "jacob", 25));setObjComparatorByAge.add( new Person( "meteor", 23));setObjComparatorByAge.add( new Person( "kitty", 22));setObjComparatorByAge.add( new Person( "tom", 26));for (Iterator<Person> it = setObjComparatorByAge.iterator(); it .hasNext();) {System.out.println( it.next());}}}
运行结果
字符串(自然排序):
awesome
java
linkedhashset
treeset
zzz
字符串(比较器):
linkedhashset
treeset
awesome
java
zzz
自定义类(自然排序):
Person [name=jacob, age=25]
Person [name=kitty, age=22]
Person [name=meteor, age=23]
Person [name=tom, age=26]
自定义类(比较器):
Person [name=kitty, age=22]
Person [name=meteor, age=23]
Person [name=jacob, age=25]
Person [name=tom, age=26]
本文详细解析Java集合框架中的Set集合,包括其特点、继承关系、常用方法、HashSet集合特性、关于hashCode和equals方法的作用、元素唯一性示例、不保证元素存取顺序、比较器的应用、LinkedHashSet集合保持元素存取顺序的能力、TreeSet集合的有序性与自定义排序方式。通过示例代码展示了如何使用和理解Set集合。
220

被折叠的 条评论
为什么被折叠?



