黑马程序员—Java集合框架(Set、HashSet、TreeSet)

------- android培训java培训、期待与您交流! ----------

 

 * Set子接口:元素是无序的(存入和取出的顺序不一定一致),元素是不可以重复的。
 *   |--HashSet:底层数据结构是哈希表。HashSet是如何保证元素的唯一性呢?
 *   |   是通过元素的两个方法,hashCode和equals来完成。如果两个元素的hashCode值相等,才会判断
 *   |   equals是否为true。如果元素的hashCode值不同,那么就不会调用equals。
 *   |   注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法.
 *   |
 *   |--TreeSet:对Set集合中的元素的进行指定顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。

 

HashSet: Set 接口的典型实现,大多数时候使用 Set 集合时都使用这个实现类。
HashSet Hash 算法 来存储集合中的元素,因此具有很好的存取和查找性能。
HashSet 具有以下特点:
不能保证元素的排列顺序
HashSet 不是线程安全的
集合元素可以使 null
当向 HashSet 集合中存入一个元素时, HashSet 会调用该对象的 hashCode () 方法来得到该对象的 hashCode 值,然后根据 hashCode 值决定该对象在 HashSet 中的存储位置。
如果两个元素的 equals() 方法返回 true ,但它们的 hashCode () 返回值不相等, hashSet 将会把它们存储在不同的位置,但依然可以添加成功。
 

哈希表的原理:

1,对对象元素中的关键字(对象中的特有数据),进行哈希算法的运算,并得出一个具体的算法值,这个值 称为哈希值。

2,哈希值就是这个元素的位置。

3,如果哈希值出现冲突,再次判断这个关键字对应的对象是否相同。如果对象相同,就不存储,因为元素重复。如果对象不同,就存储,在原来对象的哈希值基础 +1顺延。

4,存储哈希值的结构,我们称为哈希表。

5,既然哈希表是根据哈希值存储的,为了提高效率,最好保证对象的关键字是唯一的。

  这样可以尽量少的判断关键字对应的对象是否相同,提高了哈希表的操作效率。

 

hashCode() 方法

HashSet 集合判断两个元素相等的标准:两个对象通过 equals() 方法比较相等,并且两个对象的 hashCode () 方法返回值也相等。
如果两个对象通过 equals() 方法返回 true ,这两个对象的 hashCode 值也应该相同。
重写 hashCode () 方法的基本原则
在程序运行时,同一个对象多次调用 hashCode () 方法应该返回相同的值
当两个对象的 equals() 方法比较返回 true 时,这两个对象的 hashCode () 方法的返回值也应相等
对象中用作 equals() 方法比较的 Field ,都应该用来计算 hashCode

 

代码示例:

//Person类
class Person
{
	//属性name
	private String name;
	//属性age
	private int age;
	//构造函数
	public Person(String name, int age)
	{
		this.name = name;
		this.age = age;
	}
	
	//重写hashCode方法
	public int hashCode()
	{
		System.out.println(this.name+"--hashCode");
		return name.hashCode()+age*37;
	}
	//重写equals方法
	public boolean equals(Object obj)
	{
		//判断是否属于Person类型,如果不是直接返回false
		if (!(obj instanceof Person))
			return false;
		//强转为Person类型
		Person p = (Person) obj;
		System.out.println(this.name+"--equals--"+p.getName());
		//根据Person类型,定义自己独特的比较规则
		return this.name.equals(p.getName()) && this.age == p.getAge();
	}
	
	//getName方法
	public String getName()
	{
		return name;
	}
	
	//getAge方法
	public int getAge()
	{
		return age;
	}
}


 

 TreeSet:可以对Set集合中的元素进行排序。底层数据结构是二叉树。保证元素唯一性的依据就是compareTo的return返回值。
 *               后存入的元素调用compareTo方法并传入前面的元素进行比较,如果compareTo方法return返回正数就表示比前面元素大,
 *               就存到了二叉树的右边,取出时是后取出该元素的。
 *               如果return返回0,则两个元素一样,则不会存入。
 *               如果return返回负数表示比前面元素小,就存在二叉树的左边,取出时会先取出该元素。
 *              
 *               TreeSet排序的第一种方式:让元素自身具备比较性。元素需要实现Comparable接口,重写compareTo方法。
 *               这种方式也称为元素的自然顺序,也叫元素的默认顺序。
 *              
 *               TreeSet集合第二种排序方式:当元素自身不具备比较性或者具备的比较性不是所需要的,这时需要让集合自身具备比较性。
 *               让集合一初始化就有了比较方式。定义比较器类,实现Comparator接口,重写compare()方法。

自然排序:

排序: TreeSet 会调用集合元素的 compareTo (Object obj ) 方法来比较元素之间的大小关系,然后将集合元素按升序排列
如果试图把一个对象添加到 TreeSet 时,则该对象的类必须实现 Comparable 接口。
实现 Comparable 的类必须实现 compareTo (Object obj ) 方法,两个对象即通过 compareTo (Object obj ) 方法的返回值来比较大小。
因为只有相同类的两个实例才会比较大小,所以 TreeSet 中添加的应该是同一个类的对象
当需要把一个对象放入 TreeSet 中,重写该对象对应的 equals() 方法时,应保证该方法与 compareTo (Object obj ) 方法有一致的结果 :如果两个对象通过 equals() 方法比较返回 true ,则通过 compareTo (Object obj ) 方法比较应返回 0
注意:当排序时,主要条件相同时,一定要判断次要条件

 

代码示例:

//学生类,实现了Comparable接口,该接口强制让学生具备比较性。
class Student implements Comparable
{
	//name属性
	private String name;
	//age属性
	private int age;
	//构造函数
	public Student(String name, int age)
	{
		this.name = name;
		this.age = age;
	}
	//getName方法
	public String getName()
	{
		return name;
	}
	//getAge方法
	public int getAge()
	{
		return age;
	}
	
	//重写compareTo方法,当Student类的对象存入二叉树数据结构的集合,如TreeSet集合时,会根据此方法进行对象之间的比较
	public int compareTo(Object obj)
	{
		//判断要比较的对象是否是学生类型,不是则直接抛出异常
		if (!(obj instanceof Student))
			throw new RuntimeException("不是学生对象!");
		//强转为学生类型
		Student s = (Student) obj;
		//如果两个对象age值相同
		if (this.age == s.age)
			//则比较两对象的name值
			return this.name.compareTo(s.name);
		//返回两对象age值的比较结果
		return this.age-s.age;
	}
}


 

 

定制比较器:

如果需要实现定制排序,则需要在创建 TreeSet 集合对象时,提供一个 Comparator 接口的实现类对象。由该 Comparator 对象负责集合元素的排序逻辑
 
代码示例:
import java.util.Comparator;

//定义一个比较器类
class MyCompare implements Comparator
{
	//重写compare方法,比较o1和o2对象
	public int compare(Object o1, Object o2)
	{
		//将o1对象和o2对象转换成Student类型
		Student s1 = (Student) o1;
		Student s2 = (Student) o2;
		
		//如果两个对象的name属性相等时,就比较age属性值
		if (s1.getName().compareTo(s2.getName()) == 0)
			//返回两个对象的age属性值的比较结果
			return s1.getAge() - s2.getAge();
		// 返回两个对象name属性值的比较结果
		return s1.getName().compareTo(s2.getName());
	}
}

 

------- android培训java培训、期待与您交流! ----------
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值