Java集合学习之Collection(2)

上篇博客讲了Collection接口的一些基本操作,这篇博客主要介绍Collection接口的子接口Set。 Set是一种无序的集合,其基本操作和Collection接口是差不多的,主要的不同点在于Set中不能重复元素而Collection集合是可以的。对于Set集合我们主要关心它的HashSet,TreeSet两个实现类。

一.HashSet HashSet是Set接口的典型实现,大多数时候使用Set集合时就是使用这个类;HashSet通过hash算法确定元素的存储位置。值得注意的是HashSet中可以存储值为null的元素。 那么HashSet是怎样工作的呢?我们每传入一个元素,HashSet就调用该对象的HashCode()方法计算得到该对象的HashCode值,然后就根据这个值决定该元素在HashSet中的存储位置。如果两个对象通过equals()比较相等,但是计算出的HashCode值不相同,那么HashSet就将他们存储到不同的位置上去;如果两个对象的HashCode值相等,而通过equals()方法比较不相等,那么HashSet就将他们在同一个位置上以链表的形式存储。 综上我们可以知道HashSet判断两个对象相等的标准是:两个对象的HashCode值相同,并且两个对象通过equals()方法比较返回true。所以这两个方法对HashSet来说是十分重要的,我们需要保证当两个对象的HashCode值一样时,,其通过equals()方法比较也会返回true。下面的程序中A,B,C类分别重写了自己的HashCode()和equals()方法。

public class A {///重写A类的equals()方法,使其总是返回truepublic boolean equals(Object obj){return true;}}public class B {(){return 2;}}public class C {///重写C类的equals()方法,使其总是返回truepublic boolean equals(Object obj){return true;}(){return 3;}}public class HashCodeTest {(String[] args){HashSet st = new HashSet();//依次添加两个A,B,C类对象st.add(new A());st.add(new A());st.add(new B());st.add(new B());st.add(new C());st.add(new C());//可以看到只输出了一个C类,而A,B类都输出了两个System.out.println(st);}}

HashSet有一个叫LinkedHashSet的子类,LinkedHashSet的基本原理和HashSet是一样的,只是LinkedHashSet内部通过一个链表来维护插入元素的相对顺序,这样使得看起来元素是以插入的顺序保存的;当我们遍历LinkedHashSet时就可以将元素以其输入顺序输出了。

package lkl;import java.util.LinkedHashSet;public class LinkedHashSetTest {(String[] args){LinkedHashSet lt = new LinkedHashSet();lt.add(“java”);lt.add(“c”);lt.add(“c++”);lt.add(“shell”);///从下面两次输出可以看出,元素总是以输入顺序输出System.out.println(lt);lt.remove(“java”);lt.add(“java”); ///从新添加后java被放到最后System.out.println(lt);}}

二.TreeSet TreeSet是Set的另一个重要的子类。与HashSet通过hash的方式确定元素的存储位置不同,TreeSet内部通过一棵红黑树来维护元素的相对次序;由于TreeSet中元素的有序性,相对HashSet,还提供了几个额外的方法,如下面的代码所示:

package lkl;import java.util.TreeSet;public class TreeSetTest {(String[] args){TreeSet ts = new TreeSet();ts.add(1);ts.add(-2);ts.add(7);ts.add(4);///从下面的输出可以看出TreeSet是有序的System.out.println(ts);如果采用了自然排序,则返回nullSystem.out.println(ts.comparator());///Object first():返回集合中第一个元素///Object last():返回集合中最后一个元素System.out.println(“集合中第一个元素为: “+ts.first());System.out.println(“集合中最后一个元素为: “+ts.last());如果没有元素满足的话,返回nullSystem.out.println(“集合中第一个小于5的元素是: “+ts.lower(5));System.out.println(“集合中第一个大于5的元素是: “+ts.higher(5));///SortedSet subSet(Object e1,Object e2):返回Set从e1-e2之间的子集System.out.println(ts.subSet(1,5));///SortSet headSet(Object e):返回集合中小于e的元素组成的子集System.out.println(ts.headSet(6));///SortSet tailSet(Object e):返回集合中大于等于e元素组成的子集System.out.println(ts.tailSet(1));}}

因为TreeSet是有序的,所以插入一个元素时总是要比较大小;这里进行大小比较时总是调用对象obj1.compareTo(Object obj2)方法(返回正整数表示obj1大于obj2,返回负整数时表示obj1小于obj2,返回0时表示相等),只有两个对象通过compareTo()比较返回0时,才认为两个对象相等。这导致一个问题,不同的对象不能被同时插入到TreeSet中,因为不同的对象不能通过comparaTo()方法进行比较;当我们将不同的对象插入到TreeSet中时会引发异常。 如果我们想自己定义排序的规则,我们可以借助Comparator接口。该接口中包含了一个int compare(T t1,T t2)的方法,该方法在t1>t2时返回正整数,在t1

package lkl;import java.util.TreeSet;import java.util.Comparator;public class TreeSetComparatorTest {(String[] args){TreeSet ts = new TreeSet(new Comparator(){(Object o1,Object o2){int m1= (int)o1;int m2= (int)o2;if(m1==m2)return 0;if(m1>m2)return -1;return 1;}});ts.add(1);ts.add(2);ts.add(-1);System.out.println(ts);}}

最后要强调一句,如果我们向set中添加了可变的对象,然后又改变了该对象中的File,那么可能造成该对象在set中”不可见”的情况;如果我们向set中加入了可变的对象,那么我们不要在后面再改变其中File的值。

在乎的是看风景的心情,旅行不会因为美丽的风景终止。

Java集合学习之Collection(2)

相关文章:

你感兴趣的文章:

标签云: