java集合排序-----原理

本文详细探讨了Java集合框架中的HashSet、HashMap、TreeSet的工作原理,重点讲解了如何通过重写equals()、hashCode()和compareTo()方法来实现数据的唯一性和排序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.ArrayList存放的顺序按照放进去的顺序

2.HashSet不管怎么放,他会按照自己的排序给放好(这一点还是有点不明白,难道是他的hashcode写法和别人的不一样),不允许有重复数据。

3.TreeSet会升序排列。

4.HashMap以键值对的形式存放数据,可以出现null.

。。。。

 

当然还有很多关于集合的一些理论,童鞋们,看了那些每个集合的特点之后,你是不是又很多感觉到奇怪的地方,为什么HashSet不能出现重复的数据,为什么TreeSet能够实现升序排列?他们怎么知道怎样排序的,怎么排序的?相信如果你刚看集合,一定也会有这样的一个疑惑!

 

首先我们看一下众神之父Object类,他有两个方

    public native int hashCode();

    public boolean equals(Object obj)
    {
        return this == obj;
    }


理解了这两个方法我们就能理解HashSet是怎么实现将重复数据排除的。

我们测试一下HashSet,对象为String

 

public class SetTest
{
	public static void main(String[] args)
	{
		Set<String> set = new HashSet<String>();
		
		set.add("cxm");
		
		set.add("cxm");
		
		System.out.println(set.size());
	}
}

 

我们插入同样的字符:cxm,输出set的大小:

1

 

为什么呢?

因为String本身重写了

 

    public int hashCode()
    {
        int i = hash;
        if(i == 0 && count > 0)
        {
            int j = offset;
            char ac[] = value;
            int k = count;
            for(int l = 0; l < k; l++)
                i = 31 * i + ac[j++];

            hash = i;
        }
        return i;
    }


 

 

    public boolean equals(Object obj)
    {
        if(this == obj)
            return true;
        if(obj instanceof String)
        {
            String s = (String)obj;
            int i = count;
            if(i == s.count)
            {
                char ac[] = value;
                char ac1[] = s.value;
                int j = offset;
                int k = s.offset;
                while(i-- != 0) 
                    if(ac[j++] != ac1[k++])
                        return false;
                return true;
            }
        }
        return false;
    }


 

这样本身的String就已经有了比较的规则,同理如果有个对象Customer,我们向往常一样往HashSet插入,看一下效果:

 

public class Customer
{
	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;
	}

	
	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());
	}
}

我们创建了两个Customer对象,看上去这两个对象属性一样,但是往HashSet中添加时,并没有过滤到重复的数据。

2

 

 

 

那么我们怎么样让他过滤掉重复数据呢?

我们重写上面我们说的那两个方法,试试看:

	@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;
	}
	
	@Override
	public int hashCode() 
	{
		int result;
		result = (name == null ? 0 : name.hashCode());
		return result;
	}

运行一下看一下结果:

1


 

所以说,eauqls()和hashCode()提供了对象与对象之间比较规则,如果想要实现HashSet中类似的方法,现在应该知道怎么做了吧!

 

 

 

下面我们再来讨论一下TreeSet等中的升序排列了,同样

对象只要实现Comparable<Object>,实现其中的:

 

	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;
	}


 

这样两个对象就知道按照什么样的规则进行比较大小了:

public class Customer implements Comparable<Object> 
{
	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;
	}
	
	@Override
	public int hashCode() 
	{
		int result;
		result = (name == null ? 0 : name.hashCode());
		 result = 29 * result + age;
		return result;
	}

	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;
	}


	
	public static void main(String[] args)
	{
		Set<Customer> set = new TreeSet<Customer>();
		Customer customer1 = new Customer("Mom", 16);
		Customer customer2 = new Customer("Mom", 19);
		set.add(customer1);
		set.add(customer2);
		
		for(Customer Customer :set )
		{
			System.out.println(Customer.getAge());
		}
//		System.out.println(set.size())
	}
}

看一下结果:我们预期的结果是16永远在前面:

 

16
19


 

第二次执行的结果:

 

16
19


 

这样就实现了升序排列了,其实不管是比较是否相同,还是比较大小,对象中的规则都是我们设计对象的时候定的,只要我们复写以上的几个方法,就已经指定了比较的规则,就能实现上面说的那些功能了。

 

总结一下:

一: 如果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.

 

题外话:

如果两个对象equals(),那么他们的hashCode是否一定相等?


 


 

 


 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值