您的位置:首页 > 职场人生

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

2014-04-13 23:50 489 查看
------- 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(Objectobj)方法来比较元素之间的大小关系,然后将集合元素按升序排列
•如果试图把一个对象添加到 TreeSet时,则该对象的类必须实现Comparable接口。
•实现 Comparable的类必须实现compareTo(Objectobj)方法,两个对象即通过compareTo(Objectobj)方法的返回值来比较大小。

•因为只有相同类的两个实例才会比较大小,所以向TreeSet中添加的应该是同一个类的对象
•当需要把一个对象放入 TreeSet中,重写该对象对应的equals()方法时,应保证该方法与compareTo(Objectobj)方法有一致的结果:如果两个对象通过equals()方法比较返回true,则通过compareTo(Objectobj)方法比较应返回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培训、期待与您交流! ----------
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: