`
byandby
  • 浏览: 1696458 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

使用TreeSet集合比较Comparable接口和Comparator接口的区别

阅读更多
   ThreeSet能够对集合中的对象排序,当TreeSet想集合中加入一个对象时,会把它插入到有序的对象序列中。那么TreeSet是如何排序呢?TreeSet支持两种排序方式:自然排序和客户化排序.在默认情况下TreeSet采用自然排序方式。
    先来介绍介绍什么是自然排序吧
  1、自然排序
   在JDK类库中,有一部分类实现了Comparable接口,如Integer Double和String等。
Comparable接口有一个comparTo(Object o)方法,它返回整数类型。对于表达式x.compareTo(y),如果返回值为0,则表示x和y相等,如果返回值大于0,则表示x大于y,如果返回值小于0,则表示x小于y.TreeSet集合调用对象的compareTo()方法比较集合中的大小,注意鸟 不是TreeSet调用它自己的comparTo()方法而是它调用集合中对象的comparTo()方法.TreeSet类本身并没有实现Comparable接口,然后进行升序排列,这种方式称为自然排序.
   有人可能要问TreeSet集合怎么给对象排序的按对象的什么排序的?
   下面简单总结一哈
    JDK类库中实现了Comparable接口的一些类的排序方式
类 BigDecimal BigInteger Byte Double Float Integer Long Short 排序方式是按数字大小排序
类 Character是按字符的Unicode值的数字大小排序
类 String是按字符中字符的Unicode值排序


这里一定要灰常注意:使用自然排序时只能向集合中加入同类型的对象,并且这些对象的类必须实现Comparable接口
  下面来说说Comparable接口和Comparator接口的区别
Comparator位于包java.util下,而Comparable位于包   java.lang下

Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口)  此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

  比如你有一个Customer类 想让这个类的实例加入集合后自动就具有某种排序功能只要这些实例加入集合后 就会按照你给Customer对象设定的方式排序
代码:
package hang.jihe;

import java.util.HashSet;
import java.util.Set;

public class Customer implements Comparable {
	private String name;

	private int age;

	public Customer(String name, int age) {
		this.age = age;
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (!(obj instanceof Customer))
			return false;
		final Customer other = (Customer) obj;

		if (this.name.equals(other.getName()) && this.age == other.getAge())
			return true;
		else
			return false;
	}

	public static void main(String[] args) {
		Set<Customer> set = new HashSet<Customer>();
		Customer customer1 = new Customer("Tom", 15);
		Customer customer2 = new Customer("Tom", 15);
		set.add(customer1);
		set.add(customer2);
		System.out.println(set.size());
	}

	public int compareTo(Object o) {
		Customer other = (Customer) o;

		// 先按照name属性排序
		if (this.name.compareTo(other.getName()) > 0)
			return 1;
		if (this.name.compareTo(other.getName()) < 0)
			return -1;

		// 在按照age属性排序
		if (this.age > other.getAge())
			return 1;
		if (this.age < other.getAge())
			return -1;
		return 0;
	}

	@Override
	public int hashCode() {
		int result;
		result = (name == null ? 0 : name.hashCode());
		result = 29 * result + age;
		return result;
	}
}


main方法的类
package hang.jihe;

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class CustomerTester {
	public static void main(String[] args) {
		Set<Customer> set = new TreeSet<Customer>();
		set.add(new Customer("Tom",15));
		set.add(new Customer("Tom",20));
		set.add(new Customer("Tom",15));
		set.add(new Customer("Mike",15));
		
		Iterator<Customer> it = set.iterator();
		while(it.hasNext()){
			Customer customer = it.next();
			System.out.println(customer.getName()+" "+customer.getAge());
		}
	}
}


//打印结果
Mike 15
Tom 15
Tom 20


有人会问 重写hashCode()方法 equals方法干嘛 别急 慢慢道来

实际上,所有实现 Comparable 的 Java 核心类都具有与 equals 一致的自然排序。java.math.BigDecimal 是个例外,它的自然排序将值相等但精确度不同的 BigDecimal 对象(比如 4.0 和 4.00)视为相等。为了保证TreeSet能正确地排序,要求Customer类的compareTo()方法与equals()方法按相同的规则比较两个Customer对象是否相等.也就是说,如果customer1.equals(customer2)为True,那么customer1.compareTo(customer2)为0。 既然重写了equals方法 就得重写hashCode()方法这个大家都知道
大家看一眼结果便知 这个按照升序排序的  年龄也是按照升序

  还有要注意哦,对于TreeSet中已经存在的Customer对象,如果修改了它们的name属性或age属性,则TreeSet不会对集合进行重新排序.例如下边的代码先把customer1和customer2 对象加入到TreeSet集合中,然后修改customer1的age属性
代码:
package hang.jihe;

import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class TreeSetTest {
	public static void main(String[] args) {
		Set<Customer> set = new TreeSet<Customer>();
		Customer customer1 = new Customer("Tom",15);
		Customer customer2 = new Customer("Tom",16);
		set.add(customer1);
		set.add(customer2);
		//customer1.setAge(20);//修改customer1实例的age
		
		Iterator<Customer> it=set.iterator();
		while(it.hasNext()){
			Customer customer=it.next();
			System.out.println(customer.getName()+" "+customer.getAge());
		}
	}
}

  上边我先把
customer1.setAge(20);
这句注释掉
打印结果是:
Tom 15
Tom 16
这个是我们要的结果 name 和age都是按照升序排序的
然后我们把那句取消注释之后的打印结果是:
Tom 20
Tom 16

Tom 20如果按照升序应该在下边 但是却在上边 说明TreeSet没有给它重新排序哦在实际应用中Customer对象的name属性和age属性肯定应该是可以被修改的,因此不适合用TreeSet来排序。那大家也应该能想到最适合用TreeSet排序的就是不可变类了呗 比如Integer,Double,String等 所谓不可变类,是指当创建了这个类的实例后,就不允许修改它的属性值。大家以后用还是小心点好儿!

   客户化排序
   Comparator这个单词啥意思? 你知道不? 比较器的意思 学好英语还是挺好滴
   除了自然排序,TreeSet还支持客户化排序.java.util.Comparator<Type>接口提供具体的排序方式,<Type>指定被比较的对象的类型,Comparator有个compar(Type x,Type y)方法,用于比较两个对象的大小,当compare(x,y)大于0时表示x大于y,小于0表示x小于y
等于0表示x等于y
   来个例子如果希望TreeSet按照Customer对象的name属性进行降序排列,可以先创建一个实现Comparator接口的类
代码:
package hang.jihe;

import java.util.Comparator;
import java.util.Iterator;
import java.util.Set;
import java.util.TreeSet;

public class CustomerComparator implements Comparator<Customer>{

	public int compare(Customer c1, Customer c2) {
		if(c1.getName().compareTo(c2.getName())>0)return -1;
		if(c1.getName().compareTo(c2.getName())<0)return 1;
		
		return 0;
	}
	
	public static void main(String args[]){
		Set<Customer> set = new TreeSet<Customer>(new CustomerComparator());
		
		Customer customer1= new Customer("Tom",15);
		Customer customer3= new Customer("Jack",16);
		Customer customer2= new Customer("Mike",26);
		set.add(customer1);
		set.add(customer2);
		set.add(customer3);
		
		Iterator<Customer> it = set.iterator();
		while(it.hasNext()){
			Customer customer = it.next();
			System.out.println(customer.getName()+" "+customer.getAge());
		}
	}

}

  以上main方法在构造TreeSet的实例时,调用了它的TreeSet(Comparator comparator)构造方法.
Set<Customer> set = new TreeSet<Customer>(new CustomerComparator());
这是干甚? 其实就是指定一个比较器 TreeSet集合里边的对象按照这个比较器的规则进行排序 我把TreeSet类的这个构造方法搞上来看看就明白了 TreeSet里边有这样一个构造方法
TreeSet
public TreeSet(Comparator<? super E> comparator)构造一个新的空 TreeSet,它根据指定比较器进行排序。插入到该 set 的所有元素都必须能够由指定比较器进行相互比较:对于 set 中的任意两个元素 e1 和 e2,执行 comparator.compare(e1, e2) 都不得抛出 ClassCastException。如果用户试图将违反此约束的元素添加到 set 中,则 add 调用将抛出 ClassCastException。

参数:
comparator - 将用来对此 set 进行排序的比较器。如果该参数为 null,则使用元素的自然顺序。

  最后的打印结果是:
Tom 15
Mike 26
Jack 16
是倒序 ...

  那你现在是不知道了comparable接口和comparable接口的区别了并且也能更好的使用TreeSet集合了
总结一下吧
单点解释吧:用自定义类实现Comparable接口,那么这个类就具有排序功能,Comparable和具体你要进行排序的类的实例邦定。而Comparator比较灵活,只需要通过构造方法指定一个比较器就行了实现它的自定义类仅仅定义了一种排序方式或排序规则。不言而喻,这种方式比较灵活。我们的要排序的类可以分别和多个实现Comparator接口的类绑定,从而达到可以按自己的意愿实现按多种方式排序的目的。Comparable——“静态绑定排序”,Comparator——“动态绑定排序”。

  在多墨迹一点 说说编写java类时应该养成一些好习惯吧
  一: 如果java类重新定义了equals方法,那么这个类也必须重新定义hashCode()方法,并且保证当两个对象用equals方法比较结果为true时,这两个对象的hashCode()方法的返回值相等.

  二:如果java类实现了Comparable接口,那么这个类应该从新定义compareTo() equals() 和hashCode()方法,保证compareTo()和equals()方法采用相同的比较规则来比较两个对象是否相等,并且保证当两个对象用equals()方法比较的结果为true时,这两个对象的hashCode()方法的返回值相等.
   HashSet和HashMap具有较好的性能,是Set和Map首选实现类,只有在需要排序的场合,才考虑使用TreeSet和TreeMap. LinkedList 和 ArrayList各有优缺点,如果经常对元素执行插入和删除操作,那么可以用LinkedList,如果经常随机访问元素,那么可以用ArrayList.







                                                     
4
3
分享到:
评论
2 楼 sunyao1000 2010-07-03  
public int hashCode() {   
        int result;   
        result = (name == null ? 0 : name.hashCode());   
        result = 29 * result + age;   
        return result;   
    }   


这里为什么是 result = 29 * result + age; 
知道请回答
1 楼 suixinsuoyu12519 2010-06-29  
很好 很详细 

相关推荐

    【IT十八掌徐培成】Java基础第12天-02.TreeSet实现与Comparable接口.zip

    总之,`TreeSet`和`Comparable`接口是Java中处理有序集合的重要工具。通过实现`Comparable`接口或提供`Comparator`,我们可以定制元素的排序方式,满足各种复杂的业务场景。在学习和使用过程中,我们需要深入理解...

    Java中Comparable和Comparator的区别

    在Java编程语言中,Comparable和Comparator接口是两个非常重要的组件,它们主要用来进行对象的比较和排序。了解它们之间的区别对于提升代码的可维护性和灵活性至关重要。 Comparable接口来源于java.lang包,它定义...

    对比Java中的Comparable排序接口和Comparator比较器接口

    Comparator接口的一个常见用途是作为参数传递给集合框架的方法,如Collections.sort()或TreeSet/TreeMap的构造函数,以指定自定义的比较规则。例如,你可以创建一个专门比较日期的Comparator,这样在排序日期列表时...

    Java中Comparable和Comparator 2种实现方式学习

    在Java编程语言中,排序是常见的操作,而`Comparable`和`Comparator`接口则是实现对象排序的两种主要方式。这篇文章将深入探讨这两种实现方式及其在实际编程中的应用。 首先,`Comparable`接口位于`java.lang`包下...

    排序之HashSet和TreeSet的区别

    在Java编程语言中,集合框架是处理数据的重要组成部分,其中`HashSet`和`TreeSet`是两种常用的Set接口实现类。它们各自具有独特的特性和用途,理解它们的区别对于编写高效且正确的代码至关重要。 首先,`HashSet`是...

    java 中Comparable与Comparator详解与比较

    在Java编程语言中,Comparable和Comparator接口用于比较对象的顺序,尤其在进行排序操作时非常关键。两者虽然目的相似,但使用方式和应用场景有所区别。 Comparable接口定义在`java.lang`包中,它只有一个方法`...

    day18-集合-中(HashSet&TreeSet&比较器).zip

    当我们使用`TreeSet`或者对其他需要排序的集合进行自定义排序时,可以实现`Comparator`接口。`Comparator`有两个核心方法:`compare()`和`equals()`。`compare()`方法用于比较两个对象并返回一个整数值,规定了小于0...

    java 集合框架(TreeSet练习)

    1. **自然排序**:如果集合中的元素实现了`Comparable`接口,那么`TreeSet`将使用`compareTo()`方法来决定元素的顺序。 2. **自定义比较器**:如果我们需要自定义元素的排序规则,可以通过传递一个实现了`...

    Java中实现Comparable和Comparator对象比较

    此外,Comparator接口还可以用于其他数据结构,如SortedSet(如TreeSet)和SortedMap(如TreeMap),以控制其内部元素的顺序。同时,Comparator也可以用于实现复杂比较逻辑,比如多个字段的复合排序。 对于日期的...

    HashSet和TreeSet使用方法的区别解析

    如果创建TreeSet时没有指定Comparator,那么就会使用key.compareTo()方法,这就要求key必须实现Comparable接口。在TreeSet中,使用Tree数据结构来存储元素,可以确保元素的唯一性和有序性。 在实际应用中,HashSet...

    Java集合排序及java集合类详解.pdf

    内容存在一些文字错误和漏识别,但可以推断该文档详细讲解了Java集合类的各个接口以及实现类的特点、用法以及它们之间的区别,并且详细介绍了集合的排序机制,如何利用Comparable和Comparator接口实现排序,以及集合...

    HashSet和TreeSet_围墙之外

    默认情况下,元素会按照它们的自然顺序(即Comparable接口定义的顺序)排序,如果元素不支持自然排序,可以在创建TreeSet时传入自定义的Comparator。TreeSet的插入、删除和查找操作的时间复杂度为O(logn),因为内部...

    List对象集合的排序:比较器Comparator(简单例子)

    `Comparator`接口位于`java.util`包中,它包含了一个方法`compare(T o1, T o2)`,这个方法需要比较两个类型为T的对象o1和o2,并返回一个整数值。根据返回值的不同,我们可以判断o1和o2的相对大小: - 如果`compare...

    Java 集合方面的面试题

    什么是 Comparable 和 Comparator 接口?它们有什么区别? 如何使用 ConcurrentHashMap 类来实现线程安全的映射? 如何避免在多线程环境下对同一集合的并发修改? 如何使用 PriorityQueue 类实现一个最小堆? 如何...

    HashSet,TreeSet和LinkedHashSet的区别1

    在Java编程语言中,集合框架是处理数据的...在使用这些集合类时,确保正确地实现了equals()、hashCode()(对于HashSet和LinkedHashSet)以及Comparable或Comparator(对于TreeSet)方法,是保证集合行为正确性的关键。

    解决TreeSet类的排序问题

    在创建TreeSet时,传入一个实现了`Comparator`接口的实例,这样在进行比较时,就会使用这个Comparator的`compare(Object o1, Object o2)`方法。这允许我们根据特定的逻辑来对集合中的元素进行排序,比如按照年龄、...

    Java数据结构--13.Java8数据结构TreeSet.pdf

    在Java集合框架中,TreeSet是一个重要的数据结构,它是Set接口的实现类之一,与HashSet和LinkedHashSet不同,TreeSet具有排序功能,这是因为其不仅继承自AbstractSet,还实现了SortedSet和NavigableSet接口。...

    Java集合框架[汇编].pdf

    8. **Comparable接口和Comparator接口** - **Comparable**:实现了Comparable接口的类可以进行自然排序,例如Integer、String等类。 - **Comparator**:Comparator接口用于自定义比较规则,可以在不修改源类的情况...

Global site tag (gtag.js) - Google Analytics