浅谈Java hashSet

hashSet是集合的一种,是Set的一个实现类。与Set相同,都具有无序,唯一的特点。

下面是关于hashSet的一个测试:

package hashSetDemo;

import java.util.HashSet;

public class Test {
	public static void main(String[] args) {
		HashSet<Student> s=new HashSet<Student>();
		
		Student s1=new Student("叶凡",22);
		Student s2=new Student("庞博",23);
		Student s3=new Student("狠人",23);
		Student s4=new Student("无始",30);
		Student s5=new Student("姜太虚",28);
		Student s6=new Student("庞博",23);
		
		s.add(s1);
		s.add(s2);
		s.add(s3);
		s.add(s4);
		s.add(s5);
		s.add(s6);
		
		for(Student st:s) {
			System.out.println(st.getName()+"------"+st.getAge());
		}
	}
}


package hashSetDemo;

public class Student {
	private String name;
	private int age;
	public Student(String name, int age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Student() {
		super();
	}
	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;
	}
}



输出:

庞博------23
狠人------23
庞博------23
无始------30
叶凡------22
姜太虚------28

 可以看到,在这个测试中,hashSet集合并没有满足唯一的特点,这是为什么呢?

其原因是,在Set中,他的唯一性特点是通过hashCode()方法和equals()方法实现的。

而这两个方法在Student()类中并没有重写,所以默认的是使用Object中的hashCode()方法和equals()。

而Object中是通过(hash()&&equals())来判断是否有重复,而在这里面,每个对象的哈希值又不可能相同,所以

就不能保证唯一性。所以,需要在Student类中重写hashCode()方法和equals()。

 

        @Override
	public int hashCode() {
		//只有让他们的哈希值都相同,才可以继续进行equals()方法,判断内容是否相同。
		return 0;
	}
	
	@Override
	public boolean equals(Object obj) {
		// TODO 自动生成的方法存根
		if(this==obj) {
			return true;
		}
		
		//如果不是对象。直接返回false
		if(!(obj instanceof Student)) {
			return false;
		}
		
		//强制转换成Student类型
		Student s=(Student)obj;
		return this.name.equals(s.name)&&this.age==s.age;
	}


输出:

叶凡------22
庞博------23
狠人------23
无始------30
姜太虚------28

可以看到,此时的输出就没有了重复的元素, 因为重写了hashCode()方法和equals()方法。所以就可以去除重复元素了。

但是此时还是有一个问题,因为我们重写hashCode()方法的时候把哈希值默认为0,也就是说所有的对象哈希值都相等了,这个时候,每次要新加进来元素的时候,都需要和之前的元素在equals()方法中比较,如下所示:

        @Override
	public boolean equals(Object obj) {
		System.out.println(this+"------"+obj);
		// TODO 自动生成的方法存根
		if(this==obj) {
			return true;
		}
		
		//如果不是对象。直接返回false
		if(!(obj instanceof Student)) {
			return false;
		}
		
		//强制转换成Student类型
		Student s=(Student)obj;
		return this.name.equals(s.name)&&this.age==s.age;
	}


Student [name=庞博, age=23]------Student [name=叶凡, age=22]

Student [name=狠人, age=23]------Student [name=叶凡, age=22]
Student [name=狠人, age=23]------Student [name=庞博, age=23]

Student [name=无始, age=30]------Student [name=叶凡, age=22]
Student [name=无始, age=30]------Student [name=庞博, age=23]
Student [name=无始, age=30]------Student [name=狠人, age=23]

Student [name=姜太虚, age=28]------Student [name=叶凡, age=22]
Student [name=姜太虚, age=28]------Student [name=庞博, age=23]
Student [name=姜太虚, age=28]------Student [name=狠人, age=23]
Student [name=姜太虚, age=28]------Student [name=无始, age=30]

Student [name=庞博, age=23]------Student [name=叶凡, age=22]
Student [name=庞博, age=23]------Student [name=庞博, age=23]


叶凡------22
庞博------23
狠人------23
无始------30
姜太虚------28

 所以这种方法虽然可以保持唯一性的特点,但却降低了程序的效率。所以,为了不影响程序的效率,哈希值是不能设为常量的。

但是,如果不设为常量的话,每个对象的哈希值又都不相同,又不能满足唯一性的特点。为了解决这个问题,我们可以用每个对象的成员变量的哈希值来代替他们的哈希值。这样一来就可以去除掉内容重复的元素。如下:

        @Override
	public int hashCode() {
		//只有让他们的哈希值都相同,才可以继续进行equals()方法,判断内容是否相同。
		return this.name.hashCode()+this.age;
	}

        @Override
	public boolean equals(Object obj) {
		System.out.println(this+"------"+obj);
		// TODO 自动生成的方法存根
		if(this==obj) {
			return true;
		}
		
		//如果不是对象。直接返回false
		if(!(obj instanceof Student)) {
			return false;
		}
		
		//强制转换成Student类型
		Student s=(Student)obj;
		return this.name.equals(s.name)&&this.age==s.age;
	}


输出:

Student [name=庞博, age=23]------Student [name=庞博, age=23]。

姜太虚------28
无始------30
庞博------23
叶凡------22
狠人------23

 

可以看出,这个时候在equals()方法中比较的次数明显少了很多,但是这样写的话还是会有一个问题。

假如:

一个学生的姓名的哈希值为20,年龄为50。

而另一个的姓名的哈希值为30,年龄为40。

这个时候,这两个对象返回的哈希值是相等的,就又需要在equals()方法中进行比较。

 

所以可以将hashCode()方法中的返回语句改为:

        @Override
	public int hashCode() {
		//只有让他们的哈希值都相同,才可以继续进行equals()方法,判断内容是否相同。
		return this.name.hashCode()+this.age*11;
	}

这个时候就可以解决上面说的问题。

如此一来,hashSet集合就算是基本完善了,可以保证无序,唯一的特点了 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值