您的位置:首页 > 编程语言 > Java开发

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

2012-10-21 21:08 302 查看
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是否一定相等?


 

 

 

 

 

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