接口Set的特性及其实现类

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语言中,规定:相等的对象应该拥有相同的哈希编码。


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值