1、Set是Collection接口的子接口,其特性如下:
1) 元素是无序的。2) 元素不重复。当添加重复的元素时,会采用屏蔽技术屏蔽掉。
3) 它的常用实现类为: HashSet。
案例1:验证Set中的元素是否重复有序。
import java.util.HashSet;
import java.util.Set;
public class SetTest {
public static void main(String[] args) {
Set s1 = new HashSet();
//验证元素是否有序
s1.add("a1");
s1.add("a321");
s1.add("a5");
s1.add("a3");
s1.add("a213");
s1.add("a6");
s1.add("a132");
s1.add("a2");
s1.add("a4");
System.out.println(s1 + " 注意元素是否有序!");
//验证元素是否重复
s1.add("a4");
System.out.println(s1 + " 注意元素是否重复!");
}
}
结果:
[a132, a321, a1, a2, a3, a4, a213, a5, a6] 注意元素是否有序!
[a132, a321, a1, a2, a3, a4, a213, a5, a6] 注意元素是否重复!
结论1:Set中的元素不重复。当添加重复的元素时,会采用屏蔽技术屏蔽掉。
2、Set的实现类HashSet的特性:
1) 元素是无序的。2) 元素不重复。当添加重复的元素时,会采用屏蔽技术屏蔽掉。
3) 判断元素相等依赖equals()方法,同时,它还依赖hashCode()方法。
案例2:向HashSet实现类相关的容器中添加自定义类的对象来验证HashSet的第三点特性。
import java.util.HashSet;
import java.util.Set;
public class SetTest1 {
public static void main(String[] args) {
Set s1 = new HashSet();
// 验证HashSet实现类在判断元素相等时,依赖什么方法
s1.clear(); // 清空容器
s1.add(new Flower("a1", 9.9));
s1.add(new Flower("a4", 7.8));
s1.add(new Flower("a3", 6.9));
s1.add(new Flower("a2", 11.0));
System.out.println("s1>>>" + s1);
// 加入一个相同的对象试试有用不
s1.add(new Flower("a4", 7.8));
System.out.println("s1>>>" + s1);
}
}
class Flower {
private String name;
private double price;
public Flower(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public String toString() {
return "花名:" + name + " 花价:" + price;
}
}
结果:
s1>>>[花名:a4 花价:7.8, 花名:a3 花价:6.9, 花名:a1 花价:9.9, 花名:a2 花价:11.0]
s1>>>[花名:a4 花价:7.8, 花名:a3 花价:6.9, 花名:a4 花价:7.8, 花名:a1 花价:9.9, 花名:a2 花价:11.0]
结果与结论1矛盾。是结论1错了吗?先不要下结论这么快。
判断元素重复必然要比较元素,对象比较相等用equals()方法。
因此,重写Flower的equals()方法试试?
修改后的案例2:
import java.util.HashSet;
import java.util.Set;
public class SetTest1 {
public static void main(String[] args) {
Set s1 = new HashSet();
// 验证HashSet实现类在判断元素相等时,依赖什么方法
s1.clear(); // 清空容器
s1.add(new Flower("a1", 9.9));
s1.add(new Flower("a4", 7.8));
s1.add(new Flower("a3", 6.9));
s1.add(new Flower("a2", 11.0));
System.out.println("s1>>>" + s1);
// 加入一个相同的对象试试有用不
s1.add(new Flower("a4", 7.8));
System.out.println("s1>>>" + s1);
boolean flag = s1.contains(new Flower("a3", 6.9));
System.out.println(flag ? "找到了。" : "没找到。"); //这里应该输出没找到的
}
}
class Flower {
private String name;
private double price;
public Flower(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Flower) {
Flower f = (Flower) obj;
Double d1 = price; // 对于double类型的数进行比较,最好转换为对象后再进行比较,以防出错
Double d2 = f.price;
if (name.equals(f.name) && d1.equals(d2)) {
return true;
}
return false;
}
return false;
}
@Override
public String toString() {
return "花名:" + name + " 花价:" + price;
}
}
结果:
s1>>>[花名:a4 花价:7.8, 花名:a3 花价:6.9, 花名:a1 花价:9.9, 花名:a2 花价:11.0]
s1>>>[花名:a4 花价:7.8, 花名:a3 花价:6.9, 花名:a4 花价:7.8, 花名:a1 花价:9.9, 花名:a2 花价:11.0]
没找到。
还是与预想中的结果不一样。这是为何?
通过查找资料,得知:
在java语言中,每一个对象都有一个哈希编码(是一个整数),它由系统自动分配。
在Java语言中,规定:相等的对象应该拥有相同的哈希编码。
HashSet中比较的对象还需要重写hashCode()方法。
再次修改后的案例2:
import java.util.HashSet;
import java.util.Set;
public class SetTest1 {
public static void main(String[] args) {
Set s1 = new HashSet();
// 验证HashSet实现类在判断元素相等时,依赖什么方法
s1.clear(); // 清空容器
s1.add(new Flower("a1", 9.9));
s1.add(new Flower("a4", 7.8));
s1.add(new Flower("a3", 6.9));
s1.add(new Flower("a2", 11.0));
System.out.println("s1>>>" + s1);
// 加入一个相同的对象试试有用不
s1.add(new Flower("a4", 7.8));
System.out.println("s1>>>" + s1);
boolean flag = s1.contains(new Flower("a3", 6.9));
System.out.println(flag ? "找到了。" : "没找到。");
}
}
class Flower {
private String name;
private double price;
public Flower(String name, double price) {
this.name = name;
this.price = price;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Flower) {
Flower f = (Flower) obj;
Double d1 = price; // 对于double类型的数进行比较,最好转换为对象后再进行比较,以防出错
Double d2 = f.price;
if (name.equals(f.name) && d1.equals(d2)) {
return true;
}
return false;
}
return false;
}
@Override
public int hashCode() {
return 123; // 我让每个对象的哈希编码都一样,这样比较起来就和hashCode没关了
// return name.hashCode()+new Double(price).hashCode(); //这是更标准的写法
}
@Override
public String toString() {
return "花名:" + name + " 花价:" + price;
}
}
结果:
s1>>>[花名:a2 花价:11.0, 花名:a3 花价:6.9, 花名:a4 花价:7.8, 花名:a1 花价:9.9]
s1>>>[花名:a2 花价:11.0, 花名:a3 花价:6.9, 花名:a4 花价:7.8, 花名:a1 花价:9.9]
找到了。
结论: 在HashSet实现类中,自定义类的对象比较相等必须重写 equals()和hashCode()两个方法。
注意: 在java语言中,每一个对象都有一个哈希编码(是一个整数),它由系统自动分配。
在Java语言中,规定:相等的对象应该拥有相同的哈希编码。