Updated 2014/04/09 P518--P581
<数据结构>
ArrayList不能排序;TreeSet以有序状态保持并可防止重复。HashMap可用成对的name/value来保存与取出。LinkedList是针对经常插入或删除中间元素所设计的高效率集合。HashSet是防止重复的集合,可快速地寻找相符的元素。LinkedHashMap:类似HashMap,但可记住元素插入的顺序,也可以设定成依照元素上次存取的先后来排序。
Collections类: public static void sort(List list) =====可以传ArrayList进去
泛型意味着更好的类型安全性。
一般都是集合用到泛型,e.g 用到泛型的类(ArrayList)
public class ArrayList<E> extends AbstractList<E> implements List<E> …{
public Boolean add( E o) à这里的E用来指示可以加入ArrayList的元素类型
}
E部分会用你所声明与创建的真正类型来取代。ArrayList是AbstractList的子类,所以指定给ArrayList的类型会自动地用在AbstractList上。E类型也会用在List这个借口上。
以泛型的观点来说,extends这个关键词代表”是一个……”;extend代表extend或implement.
让对象实现Comparable类,就可以将该对象的集合传入Collection.sort()方法中。
Comparable类:
public interface Comparable<T>{ int compareTo(T o);}
Sort的另外一个重载方法:
Sort(List<T> list, Comparator<? super T> e)
public interface Comparator<T> { int compare(T o1, T o2); }
使用compareTo()方法时,List中的元素只能有一种将自己与同类型的另一个元素作比较的方法,但Comparator是独立于所比较元素类型之外的—它是独立的类
调用单一参数的sort(List o)方法代表由list元素上的compareTo()方法来决定顺序。因此元素必须要实现Comparable这个接口。 调用sort(List o, Coparator c)方法代表不会调用list元素的compareTo()方法,而会使用Comparator的compare()方法。这意味着list元素不需要实现Comparable。
从Collection的API说明文件中我们发现3个主要的接口:List/Set/Map
1) List是一种知道索引位置的集合。知道某物在系列集合中的位置。可以有多个元素引用相同的对象。
2) Set不允许重复的集合。知道某物是否已经存在于集合中。不会有多个元素引用相同的对象(被认为相等的两个对象也不行)
3) Map使用成对的键值和数据值。Map会维护与key有关联的值。两个key可以引用相同的对象,但key不能重复,典型的key会是String,但也可以是任何对象。
HashSet如何检查重复: equals()和hashCode()。默认情况下为引用相等性。如果想把两个不同的对象视为相等的,就必须覆盖从Object继承下来的hashCode()与equals()方法。
对象的状态制定规则
1) 如果两个对象相等,则a.equals(b) && a.hashCode() == b.hashCode()
2) 若两个对象有相同hash值,他们不一定相等
3) 若equals()被覆盖过,则hashCode()也必须被覆盖。
4) hashCode()的默认行为是对在heap上的对象产生独特的值,如果你没有override过hashCode(),则该class的两个对象怎样都不会被认为是相同的。
5) equals()的默认行为是执行==的比较。也就是说会去测试两个引用是否对上heap上同一个对象。如果equals()没有被覆盖过,两个对象永远都不会被视为相同的,因为不同的对象有不同的字节组合。
6) hashCode是用来缩小寻找成本,最后还是要用equals()才能认定是否真的找到相同的项目。
如果想要保持元素不重复且有序,使用TreeSet
要使用TreeSet,下列其中一项必须为真。
- 集合中的元素必须是要实现Comparable的类型。
- 使用重载,取用Comparator参数的构造函数来创建TreeSet。
HashMap<String, Integer> scores = new HashMap<String, Integer>();
scores.put(“Kathy”,42);
如果把方法声明成取用ArrayList<Animal>,它就只会取用ArrayList<Animal>参数,ArrayList<Dog>与ArrayList<Cat>都不行。但是当参数为普通的数组时,e.g Animal[] animal,传入dog数组编译却能通过,这是因为数组的类型是在运行期间检查的,但集合的类型检查只会发生在编译期间,所以在以下情况下编译不会出错,但是运行时会报错。
public void go(){
Dog[] dogs = {new Dog(), new Dog(), new Dog()};
takeAnimals(dogs);
}
public void takeAnimals(Animal[] animals){
animals[0] = new Cat();
}
如何才能传入Animal子型参数呢??使用万用字符
public void takeAnimals(ArrayList<? extends Animal> animals){
for(Animal a: animals){
a.eat();
}
}
这里的extends同时代表继承和实现。
在方法参数中使用万用字符时,编译器会阻止任何可能破坏引用参数所指集合的行为。你能够调用list中任何元素的方法,但不能加入元素。也就是说,你可以操作集合元素,但不能新增集合元素,如此才能保障执行期间的安全性,因为编译器会阻止执行期的恐怖行动。所以下面这个程序是可以的:
for(Animal a: animals){ a.eat(); }
但这个就过不了编译: animals.add(new Cat());
与万用字符等价的另一方法:
public <T extends Animal> void takeThing(ArrayList<T> list);