简述
Set 集合与 Collection 集合类似,但是它没有提供任何额外的方法。所有可以说 Set 其实就是一个 Collection,只不过其行为不同。Set 不允许包含相同的元素,如果试图把两个相同元素加入到同一个 Set 集合中,则添加操作失败,add() 方法会返回 false,并且不会增加新元素。
Set 接口下面有两个常用的子类:HashSet、TreeSet。
HashSet
HashSet 是按照 Hash 算法来存储其中的元素,因此具备有很好的存取和查找性能。
import java.util.HashSet;
import java.util.Set;
public class SetTest {
public static void main(String[] args) {
Set<String> all = new HashSet<>();
all.add("Hello");
all.add("Java");
all.add("Hello");// 重复数据
all.add("World");
all.add(null); // 添加一个 null 元素
// HashSet属于无需排列
System.out.println(all); // [null, Java, Hello, World]
}
}
通过代码输出,我们可以看到 HashSet 的几个特点:
- 不能保证元素的排列顺序,顺序可能发生变化
- 可以添加 null 的元素
另外:HashSet 不是同步的,如果多个线程同时访问一个 HashSet,如果有两个或者两个以上的线程同时修改 HashSet 集合时,必须通过代码来保证同步。
TreeSet
希望所有的内容可以自动进行排序操作,则可以使用Set的第二个子类 TreeSet。
import java.util.Set;
import java.util.TreeSet;
public class SetTest {
public static void main(String[] args) {
Set<String> all = new TreeSet<>();
all.add("Hello");
all.add("Java");
all.add("Hello");// 重复数据
all.add("World");
// 不能添加 null 元素,添加之后会报 java.lang.NullPointerException
// all.add(null);
// HashSet属于无需排列
System.out.println(all); // [Hello, Java, World]
}
}
通过输出可以看到:TreeSet 类是有序的,不能添加 null 元素。
关于数据排序的说明
通过自定义的类来进行数据的排序保存,在 Java 中如果想要对一组对象进行排序,需要使用 Comparable 比较器:
import java.util.Set;
import java.util.TreeSet;
class Book implements Comparable<Book>{
String title;
double price;
Book(String title, double price) {
this.title = title;
this.price = price;
}
public String toString() {
return "书名:" + this.title + ",价格为:" + this.price + "\n";
}
@Override
// 覆写 compareTo 方法
public int compareTo(Book o) {
// 通过 价格排序
if (this.price > o.price) {
return 1;
} else if (this.price < o.price) {
return -1;
} else {
return 0;
// 通过调用String 类的比较大小,可以正常输出
// return this.title.compareTo(o.title);
}
}
}
public class TestDemo {
public static void main(String[] args) {
// 使用 TreeSet 排序
Set<Book> all = new TreeSet<>();
all.add(new Book("Java从入门到精通", 88.6));
all.add(new Book("Java从入门到精通", 88.6));// 完全相同
all.add(new Book("JSP从入门到精通", 88.6));// 价格相同
all.add(new Book("Oracle", 89.6));// 完全不同
all.add(new Book("Android", 66.8));
Object[] obj = all.toArray();
for (int i = 0; i < obj.length; i++) {
System.out.println(obj[i].toString());
}
}
}
输出结果为:
书名:Android,价格为:66.8
书名:Java从入门到精通,价格为:88.6
书名:Oracle,价格为:89.6
上面的输出中,少了new Book("JSP从入门到精通", 88.6)
这对象; 发现 TreeSet 依靠的是 Comparable 接口中的 compareTo() 方法判断是否重复数据,所以价格重复数据不被保存。 当 compareTo() 方法返回值为 0 时,就会被 TreeSet 当做同一个对象进行处理。
关于重复元素的说明
Comparable 接口只能负责 TreeSet 子类进行重复元素的判断,它并不是真正的用于能够进行重复元素验证的操作。如果想要判断重复元素那么只能够依靠 Object 类中提供的方法:
- boolean equals(Object obj):对两个对象惊喜比较,以便确认是否相同
- int hashCode(): 返回该对象的哈希码,相同的对象必须返回相同的哈希码
import java.util.HashSet;
import java.util.Set;
class Book {
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
@Override
// 重写 Object 类中的 haseCode
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(price);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + ((title == null) ? 0 : title.hashCode());
return result;
}
@Override
// 重写 Object 中的 equals
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Book other = (Book) obj;
if (Double.doubleToLongBits(price) != Double.doubleToLongBits(other.price))
return false;
if (title == null) {
if (other.title != null)
return false;
} else if (!title.equals(other.title))
return false;
return true;
}
@Override
public String toString() {
return "书名:《" + this.title + "》,价格:" + this.price + "元。";
}
}
public class TestDemo {
public static void main(String[] args) {
Set<Book> all = new HashSet<>();
all.add(new Book("Java从入门到精通", 88.6));
all.add(new Book("Java从入门到精通", 88.6));// 完全相同
all.add(new Book("JSP从入门到精通", 88.6));// 价格相同
all.add(new Book("Oracle", 89.6));// 完全不同
all.add(new Book("Android", 66.8));
Object[] obj = all.toArray();
for (int i = 0; i < obj.length; i++) {
System.out.println(obj[i]);
}
}
}
控制台输出:
书名:《JSP从入门到精通》,价格:88.6元。
书名:《Java从入门到精通》,价格:88.6元。
书名:《Oracle》,价格:89.6元。
书名:《Android》,价格:66.8元。