Set是个接口类,有很多派生类:
在插入数据时,它通过数据的hashCode方法获取一个值,可以理解为其内部有一个map,hashCode为键,值为值。因此添加两个一样的数据时,第二个会失败。
HashSet类按照哈希算法来存取集合中的对象,存取速度比较快
TreeSet类实现了SortedSet接口,能够对集合中的对象进行排序。
1) HashSet
public static void set_Integer(){
Set<Integer> nums = new HashSet<>();
boolean bR1 = nums.add(10);
boolean bR2 = nums.add(30);
boolean bR3 = nums.add(20);
boolean bR4 = nums.add(40);
boolean bR5 = nums.add(30);
System.out.println(bR1);
System.out.println(bR2);
System.out.println(bR3);
System.out.println(bR4);
System.out.println(bR5);
for (Integer num : nums){
System.out.println(num);
}
}
输出:
true
true
true
true
false
20
40
10
30
可见两点:
1.set内存储的内容是无序的,并不是插入时的顺序;
2.相同的值不能插入,add方法返回的是false。
如果是类对象,判断两个对象是否一样时,通过类的hashCode和equals方法共同来判断。
如:定义一个Student类,重写其hashCode和equals方法,都只使用name成员变量来判断。
public class Student {
private Integer age;
private String name;
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Student(Integer age, String name) {
super();
this.age = age;
this.name = name;
}
public Student() {
super();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
//result = prime * result + ((age == null) ? 0 : age.hashCode());
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;
Student other = (Student) obj;
//if (age == null) {
//if (other.age != null)
//return false;
//} else if (!age.equals(other.age))
//return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
public static void set_Student(){
Set<Student> students = new HashSet<>();
Student stud1 = new Student(20, "张三");
Student stud2 = new Student(22, "李四");
Student stud3 = new Student(21, "王五");
Student stud4 = new Student(20, "李四");
students.add(stud1);
students.add(stud2);
students.add(stud3);
students.add(stud4);
for (Student stdu : students){
System.out.println(stdu.getName() + " -- " + stdu.getAge());
}
}
输出:
王五 -- 21
李四 -- 22
张三 -- 20
可见,姓名相同的对象没有添加成功。
2) LinkedHashSet
LinkedHashSet是HashSet的派生类,主要的区别在于:
HashSet中的数据是无序的(和插入时顺序无关)
LinkedHashSet中的数据是按插入时的顺序存储的。
如:
Set<Integer> nums = new HashSet<>();
for (int i = 10; i < 100000; i++){
nums.add(i);
}
nums.add(6 );
nums.add(5);
for (Integer num : nums){
System.out.println(num);
}
输出的值不是连续的:
Set<Integer> nums = new LinkedHashSet<>();
for (int i = 10; i < 100000; i++){
nums.add(i);
}
nums.add(6 );
nums.add(5);
for (Integer num : nums){
System.out.println(num);
}
输出插入时的顺序:
3) TreeSet
其内部使用一个红黑树算法来维护元素的顺序。
即:其内部数据是排序的。
l 方法
TreeSet<Integer> nums = new TreeSet<>(new IntComparator());
nums.add(6);
nums.add(5);
nums.add(3);
nums.add(7);
nums.add(1);
nums.add(2);
for (Integer num : nums){
System.out.print("\t" + num);
}
System.out.println("");
System.out.println(nums.toString());// [7, 6, 5, 3, 2, 1]
System.out.println(nums.first());// 第一个元素
System.out.println(nums.last());// 最后一个元素
System.out.println(nums.lower(2));// 元素2前面的元素值“3”
System.out.println(nums.higher(2));// 元素2后面的元素值“1”
TreeSet<Integer> subSet=(TreeSet<Integer>) nums.subSet(5, 2);// 值在[5,2)间的值(包含5,不包含2)
System.out.println(subSet.toString());// [5, 3]
TreeSet<Integer> headSet = (TreeSet<Integer>) nums.headSet(3);// 值在3前面的值(不包含3)
System.out.println(headSet.toString());// [7, 6, 5]
TreeSet<Integer> tailSet = (TreeSet<Integer>) nums.tailSet(3);// 值在3后面的值(包含3)
System.out.println(tailSet.toString());// [3, 2, 1]
l Int
Set<Integer> nums = new TreeSet<>();
nums.add(6);
nums.add(5);
nums.add(3);
nums.add(7);
for (Integer num : nums){
System.out.print(num + "\t");
}
输出: 3567
默认增序排序,也可以自定义排序规则:
定义一个类,创建TreeSet时由构造函数将排序类传入:
public class IntComparator implements Comparator<Integer>{
@Override
public int compare(Integer arg0, Integer arg1) {
return arg1-arg0;
}
}
使用时如下:
Set<Integer> nums = new TreeSet<>(new IntComparator());
输出: 7653
l String
上面是数字,如果是字串,则是使用的hashcode进行的比较,修改为降序如下:
public class StringComparator implements Comparator<String>{
@Override
public int compare(String o1, String o2) {
return o2.hashCode() - o1.hashCode();
}
}
使用时如下:
Set<String> strs = new TreeSet<>(new StringComparator());
strs.add("李四");
strs.add("张三");
strs.add("王五");
strs.add("a");
strs.add("d");
strs.add("b");
for (String str : strs){
System.out.print("\t" + str);
}
输出: 王五 李四 张三 d b a
l Date
Set<Date> dates = new TreeSet<>();
try {
String format = "yyyy-MM-dd HH:mm:ss";
Date date1 = stringToDate("2016-5-1 13:24:5", format);
Date date2 = stringToDate("2016-5-3 13:24:5", format);
Date date3 = stringToDate("2016-5-2 13:24:5", format);
dates.add(date1);
dates.add(date2);
dates.add(date3);
for (Date date : dates){
System.out.println(dateToString(date, format));
}
} catch (ParseException e) {
e.printStackTrace();
}
输出:
2016-05-01 13:24:05
2016-05-02 13:24:05
2016-05-03 13:24:05
降序:
public class DateComparator implements Comparator<Date>{
@Override
public int compare(Date o1, Date o2) {
if (o2.before(o1)){
return -1;
}
return 1;
}
}
Set<Date> dates = new TreeSet<>(new DateComparator());
try {
String format = "yyyy-MM-dd HH:mm:ss";
Date date1 = stringToDate("2016-5-1 13:24:5", format);
Date date2 = stringToDate("2016-5-3 13:24:5", format);
Date date3 = stringToDate("2016-5-2 13:24:5", format);
dates.add(date1);
dates.add(date2);
dates.add(date3);
for (Date date : dates){
System.out.println(dateToString(date, format));
}
} catch (ParseException e) {
e.printStackTrace();
}
输出:
2016-05-03 13:24:05
2016-05-02 13:24:05
2016-05-01 13:24:05
4) EunmSet
枚举set,暂时没找到使用场景,在网上找了一段说明,如下:
1、EnumSet中所有值都必须是指定枚举类型的值,它的元素也是有序的,以枚举值在枚举类的定义顺序来决定集合元素的顺序。
2、EnumSet集合不允许加入null元素,否则会抛出NullPointerException异常。
3、EnumSet类没有暴露任何构造器来创建该类的实例,程序应该通过它提供的static方法来创建EnumSet对象,常用的static方法如下:
static EnumSet allOf(Class elementType):创建一个包含指定枚举类里所有枚举值的EnumSet集合。
static EnumSet complementOf(EnumSet s):创建一个其元素类型与指定EnumSet里元素类型相同的EnumSet,新的EnumSet集合包含原EnumSet集合所不包含的、此枚举类剩下的枚举值。
static EnumSet copyOf(collection c):使用一个普通集合来创建EnumSet集合。
static EnumSet copyOf(EnumSet e):创建一个与指定EnumSet具有相同元素类型、相同集合元素的EnumSet。
static EnumSet noneOf(Class elementType):创建一个元素类型为指定枚举类型的空EnumSet.
static EnumSet of(E first,E...rest):创建一个包含一个或多个枚举值的EnumSet,传入的多个枚举值必须属于同一个枚举类。
static EnumSet range(E from,E to):创建包含从from枚举值,到to枚举值范围内所有枚举值的EnumSet集合。
public static void main(String[] args) {
EnumSet e1=EnumSet.allOf(Season1.class);//创建一个EnumSet集合,集合元素就是Season里的全部枚举值
System.out.println(e1);//输出[SPRING, SUMMER, FALL, WINTER]
EnumSet e2=EnumSet.noneOf(Season1.class);//创建一个EnumSet空集合,指定其集合元素是season1的枚举值
e2.add(Season1.WINTER);
e2.add(Season1.SPRING);
System.out.println(e2);//输出[SPRING, WINTER]
EnumSet e3=EnumSet.of(Season1.SUMMER, Season1.WINTER);//以指定枚举值创建EnumSet集合
System.out.println(e3);//输出[SUMMER, WINTER]
EnumSet e4=EnumSet.range(Season1.SUMMER, Season1.WINTER);
System.out.println(e4);//输出[SUMMER, FALL, WINTER]
EnumSet e5=EnumSet.complementOf(e4);
System.out.println(e5);//输出[SPRING]
}
遍历集合
主要有两种方式,for,以及迭代器:
如:
Set<Integer> nums = new HashSet<>();
nums.add(10);
nums.add(30);
for (Integer num : nums){
System.out.print(num + "\t");
}
Iterator<Integer> iter = nums.iterator();
while (iter.hasNext()){
Integer num = iter.next();
System.out.print(num + "\t");
}