读书人

菜鸟学Java(十八)

发布时间: 2013-10-03 17:28:15 作者: rapoo

初学者学Java(十八)
可变的数组-----集合类之Set接口

在前面两篇我讲了List接口和他的两个实现类,在这一篇我和大家一起探讨一下Set接口和他的实现类。

我觉的在集合的所有接口里,只有Set接口与数学上的集合的概念是最接近的,因为Set结合包含了数学上集合的三大特性中的两个:

1.不包含重复元素。

2.元素之间没有顺序。

这也是Set和List的区别。这个接口也有两个实现类:HashSet和TreeSet。

HashSet类

这个类的特点是元素的顺序是不确定的,而且不能添加相同的元素。那他是怎么判断两个元素是否相同呢?他需要满足下面这个关系式:

e==null ? e2==null : e.equals(e2)

通过上面这个表达式我们可以看出,就算是NULL,HashSet中也只能存在一个。对于非空元素,只要集合中没有能和他equals()返回true的,就可以加入。

在这个类中,并没有重新equals()方法,所以他是继承的Object类中的方法,在这里我们来看一下这个方法的源码:

public boolean equals(Object obj) {

return (this == obj);

}

大家都知道两个对象是否“==”,看的是toString()方法,我们再看一下他的源码:

public String toString()

{

return getClass().getName()+"@"+Integer.toHexString(hashCode());

}

在这里大家就可以看出他先是比较了这两个类是否是同一个类,然后再比较对象地址的哈希码表示是否相同。

这里提到了方法hashCode():返回该对象的哈希码值。

他有一下这么几个规定:

1.在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。

2.如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。

3.如果根据 equals(java.lang.Object)方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。

这段文字摘自帮助文档中,主要表达的意思是对于不同的对象会产生不同的哈希码值。

所以除非类中重写了equals()或hashCode()(String类重写了该方法),否则同类两个对象的比较是比较内存地址是否相同。

当使用 HashSet 时,hashCode()方法就会得到调用,判断已经存储在集合中的对象的hash code 值是否与增加的对象的 hashcode 值一致;如果不一致,直接加进去;如果一致,再进行 equals 方法的比较,equals 方法如果返回 true,表示对象已经加进去了,就不会再增加新的对象,否则加进去。

关于这个类的几个方法:

构造方法:publicHashSet();构造一个新的空set,其底层 HashMap 实例的默认初始容量 是16;

添加元素:public boolean add(E e):如果此 set 中尚未包含指定元素,则添加指定元素。

删除元素:public boolean remove(Object o):如果指定元素存在于此set 中,则将其移除。

迭代器:public Iterator<E>iterator():返回对此set 中元素进行迭代的迭代器。

我们来说一下最后一个方法,因为Set集合中的元素是无序的,所以我们不能像数组一样用索引一样来调用,也不能像链表一样用引用来调用。为了解决调用的问题,我们引入了迭代器的概念,并非只有HashSet类中有迭代器,每个集合中都有迭代器(包括List接口)。

迭代器有以下几个方法:

boolean hasNext():如果仍有元素可以迭代,则返回true。(换句话说,如果next 返回了元素而不是抛出异常,则返回 true)。也就是说,如果还有下一个元素就返回true。

Enext():返回下一个元素。

我们写一个程序来说明一下:

import java.util.HashSet;

import java.util.Iterator;

public class HashSetTest {

public static void main(String[]args) {

HashSet setOne = newHashSet();

setOne.add("a");

for(Iterator iter =setOne.iterator();iter.hasNext();)

{

System.out.println(iter.next());

}

}

}

这里表现了迭代器最常见的用法,也称作遍历集合。下面我们来讲一下:TreeSet

TreeSet

TreeSet类不仅实现了Set接口,也实现了SortedSet接口,因此TreeSet类在遍历集合的时候可以按自然顺序排序,也可以按自定义顺序来排序(String类是按字典的顺序排序的)。

而如何来定义排序的顺序呢?

这就要说到另一个接口了:Comparator.

这个接口定义了比较器,一般在使用TreeSet时我们会写一个这个接口的实现类,来完成我们需要的功能,例如我们要为学生的成绩按从高到低排序,可以这样写:

import java.util.*;

public class TreeSetTest {

public static void main(String[]args) {

TreeSet setOne = new TreeSet(new ComparatorOne());

setOne.add(new Person(90));

setOne.add(new Person(100));

setOne.add(new Person(80));

for(Iterator ite =setOne.iterator();ite.hasNext();)

{

System.out.println(((Person)ite.next()).getSocer());

}

}

}

class Person

{

private int socer;

public int getSocer() {

return socer;

}

public void setSocer(int socer) {

this.socer = socer;

}

public Person(int socer)

{

this.socer = socer;

}

}

class ComparatorOne implements Comparator

{

public int compare(Object o1, Object o2) {

Person personOne = (Person)o1;

Person personTwo = (Person)o2;

returnpersonTwo.getSocer()-personOne.getSocer();

}

}

因为我们想要让成绩高的排在前面,所以我们返回

personTwo.getSocer()-personOne.getSocer();

如果第一个同学的成绩高于第二个就返回负数,而在TreeSet中返回负数的排在前面。

有关TreeSet的构造方法常用的有两个:

1.public TreeSet();

2.publicTreeSet(Comparator comparator)

我们在实际应用中一般用第二个,因为我们需要自己定义比较方法。

关于Set接口我就说这么多吧。

读书人网 >编程

热点推荐