学习笔记之JavaSE(32)--JavaAPI详解7

今天学习的内容是集合类之HashSet和LinkedHashSet


与List接口不同,Set接口与Collection接口的方法完全一致。常用的集有HashSet、LinkedHashSet和TreeSet,今天先学习HashSet和LinkedHashSet。


HashSet的底层数据结构是哈希表,是不同步的。HashSet在存储元素时是以该元素的哈希值确定存储位置,在随机访问集中的元素时,不需要从头开始查找,根据哈希值就可以快速找到元素,所以HashSet提供了最快的查询速度注意HashSet可以存储null


那么HashSet是如何判断元素是否重复呢?在存储元素时,HashSet会先调用该元素的HashCode()方法得到该元素的哈希值,与集中元素的哈希值比较,判断该元素是否与集中的元素重复,如果不重复就直接存储该元素。但是由于算法的原因,不同对象的哈希值有可能相同,所以如果该元素的哈希值与集中某元素相同,HashSet还要使用equals()方法比较这两个元素是否相等。如果返回true,不会存储该元素;如果返回false,此时可以选择顺延或者串联存储。所以,当使用集存储自定义类的对象时,必须要覆盖HashCode()方法与equals()方法


由于HashSet是根据哈希值确定元素的存储位置,所以HashSet是无序的。针对这个问题,JavaAPI提供了一个HashSet的子类:LinkedHashSet,它的底层数据结构是链表和哈希表,所以LinkedHashSet是有序的,元素的顺序就是添加的顺序


HashSet和LinkedHashSet的示例程序如下:

public class Test55 {

	public static void main(String[] args) {

		// HashSet的方法都是Collection的方法
		HashSet<String> set = new HashSet<>();
		set.add("a");
		set.add("a");
		set.add("b");
		set.add("c");
		System.out.println(set);// [b, c, a] 元素不允许重复,且元素是无序的
		Iterator<String> it = set.iterator();
		while (it.hasNext()) {// 由于Set接口没有定义get()方法,所以只能用这种方式获取元素
			System.out.print(it.next());// bca
		}

		// LinkedHashSet是有序的
		LinkedHashSet<String> l_set = new LinkedHashSet<>();
		l_set.add("a");
		l_set.add("a");
		l_set.add("b");
		l_set.add("c");
		System.out.println(l_set);// [a, b, c] 元素不允许重复,且元素是有序的

		// 使用HashSet存储自定义对象
		HashSet<Person> hs = new HashSet<>();
		hs.add(new Person("张三", 21));
		hs.add(new Person("张三", 21));
		hs.add(new Person("李四", 21));
		hs.add(new Person("王五", 21));
		System.out.println(hs);// [Person [name=王五, age=21], Person [name=张三,
								// age=21], Person [name=李四, age=21]]
		Iterator<Person> it_p = hs.iterator();
		while (it_p.hasNext()) {
			Person p = it_p.next();
			System.out.println(p);// 具有相同name和age的Person对象会被视作同一个对象,不会重复存储
		}
	}
}

// 要覆盖Person的hashCode()与equals()方法
class Person {

	private String name;
	private int age;

	public Person() {
		super();
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int hashCode() { // 覆盖Object的hashCode()方法
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {// 覆盖Object的equals()方法
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

}

补充一点,列表判断元素是否相等(比如调用contains()方法时)只判断equals()方法,如下示例程序:

public class Test56 {

	public static void main(String[] args) {

		// 定义一个临时列表存储不重复的元素
		ArrayList<Person> al = new ArrayList<>();
		al.add(new Person("张三", 21));
		al.add(new Person("张三", 21));
		al.add(new Person("李四", 21));
		al.add(new Person("王五", 21));
		System.out.println(al);// 会存储相同name与age的Person对象
		al = getSingleElement(al);//调用了四次equals()方法
		System.out.println(al);// 不存储相同name与age的Person对象
	}

	public static ArrayList<Person> getSingleElement(ArrayList<Person> al) {
		// 定义一个临时列表
		ArrayList<Person> temp = new ArrayList<>();

		// 迭代al
		Iterator<Person> it = al.iterator();
		while (it.hasNext()) {
			Person p = it.next();

			// 判断该元素是否存在于临时列表中,如不存在,添加进临时列表
			if (!temp.contains(p)) {// 列表判断元素相同的依据:只判断equals()方法
				temp.add(p);
			}
		}
		return temp;
	}

}

class Person {

	private String name;
	private int age;

	public Person() {
		super();
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

	@Override
	public int hashCode() { // 覆盖Object的hashCode()方法
		System.out.println("hashCode()");
		return age;
	}

	@Override
	public boolean equals(Object obj) {// 覆盖Object的equals()方法
		System.out.println("equals()");
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}

}


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值