这篇文章主要是概括讲解Collection的Set接口分支!
目录
Set接口
Set的特点
- 无序、无下标和元素不能重复。
Set的方法实现
class Character<T,K>{
T name;
K age;
public Character(T name, K age) {
this.name = name;
this.age = age;
}
public T getName() {
return name;
}
@Override
public String toString() {
return "Character{" +
"name=" + name +
", age=" + age +
'}';
}
}
public class SetTest {
public static void main(String[] args) {
System.out.println("----add(string)-----");
//Set集合的特点:无序、无下标和元素不能重复
Set set1=new HashSet();
set1.add("张三");
set1.add("李四");
set1.add("王五");
System.out.println(set1);
set1.add("张三");
System.out.println(set1);
System.out.println("----add(obj)-----");
Set<Character> set2=new HashSet<>();
Character<String,Integer> c1=new Character<>("张三",18);
Character<String,Integer> c2=new Character<>("李四",19);
Character<String,Integer> c3=new Character<>("王五",20);
set2.add(c1);
set2.add(c2);
set2.add(c3);
System.out.println(set2);
set2.add(c3);
System.out.println(set2);
System.out.println("----remove(obj)-----");
set2.remove(c3);
System.out.println(set2);
System.out.println("----contains(obj)-----");
System.out.println(set2.contains(c2));
System.out.println(set2.contains(c3));
System.out.println("----遍历-----");
//和list差不多,这里主要举iterator迭代器
Iterator<Character> iterator = set2.iterator();
while (iterator.hasNext()){
Character next = iterator.next();
System.out.printf("%s ",next.getName());
}
}
}
//输出结果:
----add(string)-----
[李四, 张三, 王五]
[李四, 张三, 王五]
----add(obj)-----
[Character{name=王五, age=20}, Character{name=李四, age=19}, Character{name=张三, age=18}]
[Character{name=王五, age=20}, Character{name=李四, age=19}, Character{name=张三, age=18}]
----remove(obj)-----
[Character{name=李四, age=19}, Character{name=张三, age=18}]
----contains(obj)-----
true
false
----遍历-----
李四 张三
HashSet实现类
HashSet的方法实现
- HashSet是基于HashMap实现的,比如HashSet中add方法调用的是底层HashMap中的put()方法。HashSet中的元素都存放在HashMap的key上面,而value中的值都是统一的一个固定对象private static final Object PRESENT = new Object()。
class SimpleNumber{
int number;
public SimpleNumber(int number) {
this.number = number;
}
public int getNumber() {
return number;
}
@Override
public String toString() {
return "SimpleNumber{" +
"number=" + number +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SimpleNumber that = (SimpleNumber) o;
return number == that.number;
}
@Override
public int hashCode() {
return Objects.hash(number);
}
}
public class HashSetTest {
public static void main(String[] args) {
//HashSet的方法和Set接口的方法差不多
HashSet hashSet=new HashSet();
SimpleNumber s1=new SimpleNumber(8);
SimpleNumber s2=new SimpleNumber(3);
SimpleNumber s3=new SimpleNumber(4);
hashSet.add(s1);
hashSet.add(s2);
hashSet.add(s3);
System.out.println("原来的:"+hashSet);
hashSet.add(s3);
System.out.println("添加s3:"+hashSet);
//如果重写了该类的hashCode方法和equals方法,那么就不会添加新的对象元素
//如果没有重写或者只重写其中一个,新的元素还是会被添加进来
//类似:[SimpleNumber{number=3},SimpleNumber{number=4}, SimpleNumber{number=4}, SimpleNumber{number=8}]
hashSet.add(new SimpleNumber(4));
System.out.println("添加新的对象:"+hashSet);
//如果重写了该类的hashCode方法和equals方法,那么就会在集合中删除该元素
//如果没有重写或者只重写其中一个,不会删除任何元素
hashSet.remove(new SimpleNumber(4));
System.out.println("删除操作:"+hashSet);
}
}
//输出结果:
原来的:[SimpleNumber{number=3}, SimpleNumber{number=4}, SimpleNumber{number=8}]
添加s3:[SimpleNumber{number=3}, SimpleNumber{number=4}, SimpleNumber{number=8}]
添加新的对象:[SimpleNumber{number=3}, SimpleNumber{number=4}, SimpleNumber{number=8}]
删除操作:[SimpleNumber{number=3}, SimpleNumber{number=8}]
TreeSet实现类
-
TreeSet是基于TreeMap实现的,内部维持了一个简化版的TreeMap。
-
TreeSet实现了SortedSet接口,能对集合元素自动排序。
-
TreeSet元素对象的类型实现Comparable接口,指定排序规则。
TreeSet的方法实现
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<Integer> numbers = new TreeSet<>();
numbers.add(5);
numbers.add(2);
numbers.add(9);
numbers.add(4);
numbers.add(6);
numbers.add(7);
System.out.println("TreeSet: " + numbers);
// 使用 first() 方法
int first = numbers.first();
System.out.println("第一个数字: " + first);
// 使用 last() 方法
int last = numbers.last();
System.out.println("最后一个数字: " + last);
System.out.println("------------");
// 使用 higher() 返回大于指定元素(element)的最小元素
System.out.println("使用 higher: " + numbers.higher(4));
// 使用 lower() 返回小于指定元素(element)的最大元素
System.out.println("使用 lower: " + numbers.lower(4));
// 使用 ceiling() 返回大于指定元素(element)的那些元素中的最小元素。如果传递的元素(element)存在于树集中,则返回作为参数传递的元素(element)
System.out.println("使用 ceiling: " + numbers.ceiling(4));
// 使用 floor() 返回小于指定元素(element)的元素中最大的元素。如果传递的元素(element)存在于树集中,则返回作为参数传递的元素(element)
System.out.println("使用 floor: " + numbers.floor(3));
System.out.println("------------");
// 使用 pollFirst() 返回并从集合中删除第一个元素
System.out.println("删除第一个元素: " + numbers.pollFirst());
// 使用 pollLast() 返回并从集合中删除最后一个元素
System.out.println("删除最后一个元素: " + numbers.pollLast());
System.out.println("新的TreeSet: " + numbers);
System.out.println("------------");
/*
headSet(element,booleanValue)
headSet()方法返回指定元素(作为参数传递)之前的树集的所有元素
booleanValue参数是可选的。默认值为false
如果booleanValue的值为true,则该方法返回指定元素之前的所有元素,包括指定元素
*/
// 使用 headSet()使用默认的布尔值
System.out.println("headSet()使用默认的布尔值: " + numbers.headSet(5));
// 使用 headSet()使用指定的布尔值
System.out.println("headSet()带有布尔值: " + numbers.headSet(5, true));
System.out.println("------------");
/*
tailSet(element,booleanValue)
tailSet()方法返回包含指定元素的指定元素(作为参数传递)之后的树集的所有元素。
booleanValue参数是可选的。默认值为true。
如果false作为参数传递booleanValue,则该方法将返回指定后的所有元素,不包括指定的element
*/
// 使用 tailSet()使用默认的布尔值
System.out.println("tailSet()使用默认的布尔值: " + numbers.tailSet(5));
// 使用 tailSet()使用指定的布尔值
System.out.println("tailSet()带有布尔值: " + numbers.tailSet(5, false));
System.out.println("------------");
/*
subSet(e1,bv1,e2,bv2)
subSet()方法返回e1和e2之间的所有元素,包括e1。
bv1和bv2是可选参数。 bv1的默认值为true,bv2的默认值为false。
如果将false作为bv1传递,则该方法返回e1和e2之间的所有元素,而不包括e1。
如果将true作为bv2传递,则该方法返回e1和e2之间的所有元素,包括e1。
*/
// 使用 subSet()使用默认的布尔值
System.out.println("subSet()使用默认布尔值: " + numbers.subSet(4, 6));
// 使用 subSet()使用指定的布尔值
System.out.println("subSet()使用指定的布尔值: " + numbers.subSet(4, false, 6, true));
}
}
//输出结果:
TreeSet: [2, 4, 5, 6, 7, 9]
第一个数字: 2
最后一个数字: 9
------------
使用 higher: 5
使用 lower: 2
使用 ceiling: 4
使用 floor: 2
------------
删除第一个元素: 2
删除最后一个元素: 9
新的TreeSet: [4, 5, 6, 7]
------------
headSet()使用默认的布尔值: [4]
headSet()带有布尔值: [4, 5]
------------
tailSet()使用默认的布尔值: [5, 6, 7]
tailSet()带有布尔值: [6, 7]
------------
subSet()使用默认布尔值: [4, 5]
subSet()使用指定的布尔值: [5, 6]
实现Comparable接口
class Actor implements Comparable<Actor>{
private String name;
private int age;
public Actor(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Actor{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
//先按姓名排序,姓名相同再按年龄排序
public int compareTo(Actor o) {
//name升序 反过来写降序
int n1=this.getName().compareTo(o.getName());
//age降序 反过来写升序
int n2=o.getAge()-this.getAge();
return n1==0?n2:n1;
}
}
public class TreeSetTest {
public static void main(String[] args) {
TreeSet<Actor> treeSet=new TreeSet<>();
Actor a1=new Actor("jasper",18);
Actor a2=new Actor("mike",19);
Actor a3=new Actor("tom",20);
Actor a4=new Actor("tom",11);
treeSet.add(a1);
treeSet.add(a2);
treeSet.add(a3);
treeSet.add(a4);
System.out.println(treeSet);
//因为实现了Comparable接口,所以即使添加新的对象,只要比对的属性相同,就无法添加进去
treeSet.add(new Actor("tom",11));
System.out.println(treeSet);
//因为实现了Comparable接口,所以即使删除新的对象,只要比对的属性相同,就能删除
treeSet.remove(new Actor("mike",19));
System.out.println(treeSet);
}
}
//输出结果:
[Actor{name='jasper', age=18}, Actor{name='mike', age=19}, Actor{name='tom', age=20}, Actor{name='tom', age=11}]
[Actor{name='jasper', age=18}, Actor{name='mike', age=19}, Actor{name='tom', age=20}, Actor{name='tom', age=11}]
[Actor{name='jasper', age=18}, Actor{name='tom', age=20}, Actor{name='tom', age=11}]
实现Comparator定制比较
class Waiter{
private String name;
private int age;
public Waiter(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
@Override
public String toString() {
return "Waiter{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class TreeSetTest2 {
public static void main(String[] args) {
TreeSet<Actor> treeSet=new TreeSet<>(new Comparator<Actor>() {
@Override
public int compare(Actor o1, Actor o2) {
//name升序 反过来写降序
int n1=o1.getName().compareTo(o2.getName());
//age降序 反过来写升序
int n2=o2.getAge()-o1.getAge();
return n1==0?n2:n1;
}
});
Actor a1=new Actor("jasper",18);
Actor a2=new Actor("mike",19);
Actor a3=new Actor("tom",20);
Actor a4=new Actor("tom",11);
treeSet.add(a1);
treeSet.add(a2);
treeSet.add(a3);
treeSet.add(a4);
System.out.println(treeSet);
treeSet.add(new Actor("tom",11));
System.out.println(treeSet);
treeSet.remove(new Actor("mike",19));
System.out.println(treeSet);
}
}
//输出结果:
[Actor{name='jasper', age=18}, Actor{name='mike', age=19}, Actor{name='tom', age=20}, Actor{name='tom', age=11}]
[Actor{name='jasper', age=18}, Actor{name='mike', age=19}, Actor{name='tom', age=20}, Actor{name='tom', age=11}]
[Actor{name='jasper', age=18}, Actor{name='tom', age=20}, Actor{name='tom', age=11}]
HashSet和TreeSet的区别
HashSet
- HashSet内部的数据结构是哈希表(数组+链表+红黑树),是线程不安全的。
- HashSet集合元素可以是null,但只能放入一个null。
HashSet hashSet=new HashSet();
hashSet.add(null);
hashSet.add(null);//add了两次但只能存一个null
- HashSet存放对象时,通过对象的hashCode和equals方法来完成对象唯一性的判断。通过hashcode方法找到该对象存放的位置,然后通过equals方法进行比较,如果相同则不添加。
- HashSet如果同一个类向HashSet添加不同的对象,可以覆盖hashCode方法和equals方法,使其通过比较对象属性值来判断。
TreeSet
- TreeSet内部的数据结构是红黑树,是线程不安全的。
- TreeSet集合元素不允许放入null值。
TreeSet treeSet=new TreeSet();
treeSet.add(null);//运行错误 java.lang.NullPointerException
-
TreeSet可以实现Comparable接口,并覆盖其compareTo方法进行排序。TreeSet也可以实现Comparator接口,并覆盖其compare方法进行排序。
-
TreeSet存放对象时,是根据对象的compareTo方法判断两个对象是否相等,并进行比较。
Hi, welcome to JasperのBlog!