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是否一定相等?