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

黑马程序员------set和TreeSet的使用和原理

2015-12-05 01:51 501 查看
黑马程序员------set和TreeSet的使用和原理

假如有个项目,要把一个公司的员工的名字,年龄,工资做一个表单,然后可以实现点按钮就按姓名笔画或者拼音,按工资水平,按年龄或者按其他方式进行排列,当然用数据库是最好的,但是如果要求用集合呢,个人认为TreeSet是个可以考虑的类,

set的特点:

不包含重复元素

Set集合没有索引(即没有顺序)

TreeSet的特点:

底层数据结构红黑树(red-black-tree)

存储到红黑树中的对象,会进行排序

线程不安全集合,运行速度快

引入一个set案例:

/*
* Set集合存储并迭代
* Set集合代码,和List集合代码,是一样的,但是set有自己的特点
* 不接受重复的元素,输出元素自然排序
*/
import java.util.*;

public
class
SetDemo {
public
static void
main(String[] args) {
method_2();
}
/*
* Set集合存储自定义对象Person,并迭代
* 将姓名和年龄,相同的对象去掉
*/
public
static void
method_2(){
Set<Person> set = newHashSet<Person>();

set.add(new Person("c2",182));
set.add(new Person("d4",184));
set.add(new Person("a2",182));
set.add(new Person("d4",183));
set.add(new Person("c2",182));

/*
输出:输出没有顺序,不会像treeSet那样自然排序
Person [name=a2, age=182]
//有重复的被砍掉了,如果字符相同,比较数字,这主要是调用了
//person类中自带的compareTo(Person p)方法
Person [name=d4, age=184]
Person [name=d4, age=183]
Person [name=c2, age=182]
*/

Iterator<Person> it = set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}

}



程序里引用了一个类Person泛型,Person是一个标准类实现了Comparable<Person>接口,这里将person类简单写下:

package bokebao;
public
class
Person implements Comparable<Person> {
. . . . . .
@Override返回了String字符串
public String toString() {
return
"Person[name=" + name +
", age=" + age +
"]";
}
//重写了hashCode()方法
public
int
hashCode(){
return
name.hashCode()+age*31;
}
//重写了equals(Object obj)方法
public
boolean
equals(Object obj){
if(obj==null)
return
false
;
if(this==obj)
return
false
;
if(obj
instanceof Person){
Person p=(Person)obj;
return
this
.name.equals(p.name)&&this.age==p.age;
}
return
false
;
}
@Override重写了compareTo(Person p)方法

public
int
compareTo(Person p) {
// TODO Auto-generatedmethod stub
int number=this.name.compareTo(p.name);
//三目运算符,如果姓名相同,比较年龄按照年龄进行顺序输出,
return number==0?this.age-p.age:number;

}

}



为什么在类中要加这么多重写还要实现接口呢?

这就是TreeSet使用类作为泛型的一个重点和难点,也是很多小伙伴困扰的地方,我们再调一个TreeSet案例看一下:

/*
* TreeSet集合存储对象并迭代
*/
import java.util.*;

public
class
TreeSetDemo {
public
static void
main(String[] args) {
method_2();
method_1();
}
/*
*TreeSet存储自定义对象Person,并迭代
* 排序是要使用比较器对象,不使用对象的自然顺序
* 比较器优先级最高
*/
public
static void
method_2(){
//在TreeSet构造方法中,传递写好的,比较器对象
Set<Person> set = new TreeSet<Person>(new CompareDemo());
//java.util 接口 Comparator<T>

set.add(new Person("zhangsan",18));
set.add(new Person("lisi",20));
set.add(new Person("wangwu",19));
set.add(new Person("zhaoliu",17));
for(Person p : set){
System.out.println(p);
}
}

/*
*TreeSet存储自定义对象Person,并迭代
* 排序使用的是对象的自然顺序
*/
public
static void
method_1(){
Set<Person> set = new TreeSet<Person>();
set.add(new Person("zhangsan",18));
set.add(new Person("wisi",20));
set.add(new Person("vangwu",19));
set.add(new Person("uhaoliu",17));
for(Person p : set){
System.out.println(p);
}
}


}



这个案例调用了两个方法,方法1没什么好说的,还是调用了Person类的重写的hashCode()和equals(Object obj)方法,如果类返回的字符串的哈希值相同,就用equals(Objectobj)比较字母或数字,注意几个方面

1、 Person必须实现接口Comparable否则在TreeSet中它会报错,类作为泛型

对象,必须重写接口中调用的方法,否则,TreeSet方法中默认的自然排序没办法排列,类里面不重写无法实现自然排序,这点一定要注意,你会发现程序写完了,Eclipse也没有报编译错误,就是运行出错。

2、 TreeSet要实现自然顺序排序,必然要调用内部的
comparator
()
方法,
comparator
()
指定者是通过接口SortedSet<E>
中的抽象方法comparator;

返回的一个是一个抽象的接口,要实现这个接口就只有在Person类中实现,所以在类中实现了java。Lang下的接口Comparable,这样Person就可以直接调用compareTo方法了,而主方法,也可以将调用的接口实例化

为了应付不同的要求排序方式我们还可以重写Comparator接口,这样就实现了TreeSet的快速存取的排序

/*
* 自定义的比较器对象
* 实现Comparator接口
*/

public class CompareDemoimplements java.util.Comparator<Person>{
/*
* p1和p2对象的年龄,年龄相同,在比较姓名
* 注意:p1对象的age-p2对象的age
* 比较器中,不允许直接使用Person类的私有成员,必须依靠get set
*/
public int compare(Person p1, Person p2) {
//计算两个对象的年龄差
int age = p1.getAge() - p2.getAge();
return age==0? p1.getName().compareTo(p2.getName()) :age;
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: