黑马程序员------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;
返回的一个是一个抽象的接口,要实现这个接口就只有在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;
}
}
假如有个项目,要把一个公司的员工的名字,年龄,工资做一个表单,然后可以实现点按钮就按姓名笔画或者拼音,按工资水平,按年龄或者按其他方式进行排列,当然用数据库是最好的,但是如果要求用集合呢,个人认为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;
}
}
相关文章推荐
- 黑马程序员--java基础-方法重载与数组
- 115个Java面试题和答案(下)
- 115个Java面试题和答案(上)
- 黑马程序员------小练习
- 黑马程序员_简单实用 ,客户端跟服务器进行数据传输的结束标记 ,特别是被老师洗脑太深的,不看别后悔。
- 程序员必须了解的内存知识
- 程序员学习能力提升三要素
- 优秀程序员的七大特征,你具备几条?
- 优秀程序员的七大特征,你具备几条?
- 黑马程序员__Java多线程Thread
- 黑马程序员__Java输入输出流
- 黑马程序员--java基础之方法流程控制总结
- 第一篇博客,谈谈程序员
- 黑马程序员_java基础_正则表达式
- 黑马程序员——Foundation框架——NSString常用方法
- hpuoj 1720: 感恩节KK专场——面试难题【贪心】
- 王道程序员求职宝典阅读笔记20151204
- 细思极恐!未来百万人将下岗十大职业将消失
- 国内互联网公司算法&机器学习岗(阿里星)面试总结
- 2015年应届硕士生求职经验总结【算法工程师岗&无线通信研发岗】