一 我所知道的集合
我知道的第一个集合:ArrayList,加入元素非常方便,add(Object elem)。其它的, TreeSet(有序并防止重复), HashMap(名值对), LinkedList(为经常插入或删除中间元素所设计的高效集合), HashSet(防止重复,可快速找寻符合的元素), LinkedHashMap(类型于HashMap, 但可以记住元素插入的顺序,也可以设定成依照元素上次存取的先后来排序)。总的来说,这些集合可以用“顺序”和“重复”来区分。
下面两图用来说明3个主要的接口:List, Set 和 Map.(部分)
二 顺序
顺序问题,可以用TreeSet或Collections.sort()来实现。当插入新元素时,TreeSet会花时间找到适当的位置,所以相对要慢了。而ArrayList只要把新加的元素放到最后就好。(当然,ArrayList也有重载的add(index, element )可以插到指定位置,也慢,通常不这样做。)
sort(List<T> list) 方法 /* public static <T extends Comparable<? super T>> void sort(List<T> list) */ :只传入Comparable 接口的 list 作为参数。Comparable有一个方法要实现:compareTo(T o)方法。
或者用重载的sort()方法:sort(List<T> list, Comparator< ? super T> c)方法 。这样,就用不着compareTo()方法了。而是要实现Comparator接口,实现compare()方法。
实例1-关于 sort(List<T> list)
/**//* Class StudyComparable */
package conllection;
import java.util.Collections;
import java.util.LinkedList;
public class StudyComparable {
LinkedList<Person> psn = new LinkedList<Person>();
public static void main(String[] args) {
StudyComparable sc = new StudyComparable();
sc.go();
}
private void go() {
psn.add(new Person("one", 3));
psn.add(new Person("two", 2));
psn.add(new Person("three", 5));
psn.add(new Person("five", 6));
psn.add(new Person("eight", 8));
System.out.println(psn);
Collections.sort(psn);
System.out.println(psn);
}
}
/**//* Class Person */
package conllection;
public class Person implements Comparable<Person> {
String name;
int age;
public Person(String n, int a) {
name = n;
age = a;
}
@Override
public int compareTo(Person o) {
return name.compareTo(o.name);
}
@Override
public String toString() {
return name + "/" + age;
}
}
运行结果:
[one/3, two/2, three/5, five/6, eight/8]
[eight/8, five/6, one/3, three/5, two/2]
现在,可以按照name来排序了,不过我想用age 来排序,就要改代码,用Person类中的compareTo()方法进入age的比较。这样做很不好,所以可以用重载的sort(List<T> list, Comparator<? super T> c)方法。
实例2-关于 sort(List <T> list, Comparator <? super T> c)
Class StudyComparator
package conllection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
public class StudyComparator {
ArrayList<Person> psn = new ArrayList<Person>();
public static void main(String[] args) {
StudyComparator sc = new StudyComparator();
sc.go();
}
class NameComparator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
return o1.name.compareTo(o2.name);
}
}
class AgeComparator implements Comparator<Person> {
@Override
public int compare(Person o1, Person o2) {
return o1.age - o2.age;
}
}
private void go() {
psn.add(new Person("one", 3));
psn.add(new Person("two", 2));
psn.add(new Person("three", 5));
psn.add(new Person("five", 6));
psn.add(new Person("eight", 8));
System.out.println(psn);
NameComparator nc = new NameComparator();
Collections.sort(psn, nc);
System.out.println("onName:" + psn);
AgeComparator ac = new AgeComparator();
Collections.sort(psn, ac);
System.out.println("onAge:" + psn);
}
}
Class Person:同例1中的Person.Class 。因为在StudyComparator里面定义了Comparator的实现类,所以Person类不用动,也就是说,在没有原代码的情况下也实现了sort,而且可按不同的属性来进行排序,我更喜欢这个重载的sort()方法。
运行结果:
[one/3, two/2, three/5, five/6, eight/8]
onName:[eight/8, five/6, one/3, three/5, two/2]
onAge:[two/2, one/3, three/5, five/6, eight/8]
三 重复
1 相等 ==
防止重复,用Set。要解决的第一个问题:两个对象的引用怎样才算是重复?答案就是它们是相等的。那么怎样算‘相等’?显然不是单纯的值相等。‘相等’包括引用相等和对象相等。
引用相等:引用堆上的同一对象的两个引用是相等的。如果对两个引用调用hashCode() ,会得到相同的结果。hashCode()(默认的行为)会返回对象在堆上的特有的唯一序号。显然,不同对象的引用的hashCode()的值是不同的。
对象相等:堆上的两个不同对象,在意义上相同。
因此,
想要两个不同的对象‘相等’,就必须要override hashCode()和equals()方法。
a.equals(b) 的默认行为是执行‘==’,包括了hashCode()的对比。如果equals()方法不被override, 那么两个对象永远都不会视为相同。
2 HashSet 检查重复:hashCode() 与 equals()
当把对象放入HashSet时,它会先用对象的hashCode()与已有元素的hashCode()来比较,(如果没有override过hashCode()方法,那么HashSet 会认为对象间不重复,我们当然要override来确保对象有相同的值)。如果hashCode()相同,再调用其中一个的equals()来检查对象是否真的相同。如果又相同了,那么加入的操作就不会发生。
说明:有相同hashCode()的对象也不一定是相等的,感觉有点怪,但的确如此。因为hashCode()用的是杂凑算法,也许刚好使多个对象有了相同的杂凑值。越烂的杂凑算法越容易碰撞。这个属于数据结构方面的问题了。具体的要问专家了。
posted on 2008-07-09 02:47
BlueSunshine 阅读(1162)
评论(3) 编辑 收藏 所属分类:
学习心得