1.在Java SE5之前,有1个很大的问题就是编译器允许向容器中插入不正确的类型,ArrayList里面存放的是Object,里面可以存放Apple,也可以存放Orange。并且在取出元素的时候,必须强制转型,因为你取出来的都是Object类型。错误只能在运行时发现
2.在Java SE5之后,我们可以使用泛型进行预定义,如果插入的类型不对,编译器就能发现。
并且在取出元素的时候,不再需要“强制转型”,因为编译器知道正确的类型信息。
3.ArrayList<Apple>,我们可以向里面放入Apple的子类。
4.一般我们都会进行向上转型的方式生成1个具体集合类的对象(为了功能),例如:
List<Apple> list = new LinkedList<Apple>();
但是,这种方式并非总能够奏效,因为某些具体类拥有额外的功能,比如LinkedList有List没有的方法,TreeMap也具有Map接口中未包含的方法。如果你需要使用这些方法,就不能将他们向上转型为更通用的接口。
5.Collection概括了序列的概念--------------一种存放一组对象的方式。(注意,存放的是对象,当你在里面放入基本类型的时候,会进行打包机制,并且用泛型进行预定义的时候,也要使用对象Interger等)。
6.添加一组元素的方式:
关键方法:a.)Collection.addAll(Collection collection);
List<Apple> list = new ArrayList<Apple>();
List<Apple> list2= new ArrayList<Apple>();
list2.add(new Apple());
list.addAll(list2);
集合类的addAll()只能接受另一个Collection;
b.)Collections.addAll();
public static <T> boolean addAll(Collection<? super T> c,T... elements)
它接受2个参数,第一个参数必须是一个Collection,第二个参数是可变参数,所以第二个参数可以一个数组或者是逗号分割的列表。
b.1)加可变列表
Collections.addAll(list, new Apple(),new Apple(),new Apple());
b.2)加数组
Apple[] array = new Apple[]{ new Apple(),new Apple(),new Apple()};
Collections.addAll(list,array);
两种方式的总结:
Collections.addAll()运行的更快。并且接受参数更多,有数组和可变参数。
7.Arrays.asList(数组或者逗号分割的可变列表):
它接受的参数是数组或是逗号分隔的可变列表,可以转换成List,但是需要注意的是:他的底层实现用的是数组,因此不能调节尺寸,如果你试图add()或者delete()方法在这种列表中添加或删除元素,就有可能引发去改变数组尺寸的尝试,会报错。
Arrays.asList()方法的限制是他对所产生的list的类型做出了最理想的假设,例如:
class A{}
class Aa extends A{}
class Aaa extends A{}
class B extends Aa{}
class C extends Aa{}
List<A> list = Arrays.asList(new B(),new C());
List<A> list1 = Arrays.asList(new B(),new C());
list.addAll(1, list1);
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(Unknown Source)
at java.util.AbstractList.addAll(Unknown Source)
at Test.main(Test.java:11)
因为这样的时候list中只有Aa类型,它会创建的是List<Aa>而不是List<A>。
8.容器的打印:
Collection和Map类都得到了良好的封装,直接打印就可以得到结果。
不同的是Collection(list,Set,Queue等)是[x,x,x,x,x,x,x]的形式;
Map是{key1=value,key2=value2,key3=value3}的形式。
9.对比:
HashSet最快获取元素。
TreeSet比较结果的升序。
LinkedHashSet被添加的顺序。
HashMap最快查找技术。
TreeMap比较结果的升序。
LinkedHashMap被添加的顺序。
10.关于List:
有两种List:ArrayList和LinkedList。
ArrayList随机访问比较快,中间的插入和删除比较慢,如果你有很多的插入或者删除操作,避免用ArrayList。
LinkedList它通过较低的代价在List中间进行插入和删除操作,但是它不擅长随机访问,如果你有很多随机访问操作,避免用LinkedList。并且它的特性集比ArrayList更大。
方法总结:
List.add();
List.add(int index,T t);--------------中间插入
List,addAll(AnotherList);-------------在末端插入另一个list。
List.addAll(int index,AnotherList);----------------在中间插入另一个list。
List.indexOf(list中某个Object的”引用”,注意是引用,如果你只是新new了个对象,新对象和list中的对象不是equals的,所以会返回false,String类是内容完全相同的时候就equals()返回true);
List.subList(int startIndex,int endIndex);--------------获得子列表
List.contains(“某对象引用”);
List.cotainsAll(List anotherList);
List.retainAll(AnotherList);--------------------交集
List.remove(引用);
List.remove(int index);-------------通过索引移除
List.removeAll(AnotherList);
List.set(int index,T t);-------------其实用replace描述更准确,是替换元素。
List.isEmpty();
List.clear();
List.toArray();返回的是Object[]数组。
List.toArray(T[] t);返回指定数组类型。
Collections.sort(List list);--------------排序。
Collections.shuffle();-----------乱序。
11.容器生成新容器:
List<A> list = Arrays.asList(new B(), new Aaa());
LinkedList<A> link = new LinkedList<A>(list);
Collection<T> collection = new Collection<T>(AnotherCollection);
这里的Collection可以是List、Queue、Set等,也就是可以通过容器生成新的容器。
12.迭代器Iterator:
a.)Iterator是一种轻量级对象,创建它的代价很小。
b.)Iterator有一些限制,比如只能单向移动。
c.)Collection.iterator()返回1个Iterator。
hasNext();
next();
remove();(它会移除由next()产生的最后一个元素,所以remove()在next()之后出现,并且一起出现);
d.)迭代器可以不管你Collection的类别,无论你是List、Set、Queue,如果你的程序代码需要将一份代码同时应用于多种Collection情况,那么你应该做的是用Iterator来实现你的代码。
一句话:Iterator统一了对容器的访问方式。
public void play(Iterator<Apple> it){
Apple apple = it.next();
Apple.xxxxx(某某方法);
}
play(new HashSet<Apple>().Iterator);
play(new TreeSet<Apple>().Iterator);
play(new List<Apple>().Iterator);
play(new LinkedList<Apple>().Iterator);
e.)ListIterator:
它是一个更强大的Iterator的子类型,
(1)它只能作用于各种List类型的访问。
(2)它可以双向移动。
List<A> list = Arrays.asList(new B(), new Aaa());
ListIterator<A> listIterator1=list.listIterator();
ListIterator<A> listIterator2=list.listIterator(2);
System.out.println(listIterator2.hasNext());
listIterator1.next();
listIterator1.previous();
listIterator1.set(new A());
listIterator1.hasPrevious();
List.listIterator(n)索引一开始就指向n;
set(T a)方法替换它最后访问的元素。
previous();向前移动
hasPrevious();
13.LinkedList:
它在中间插入删除操作更优秀,并且添加了可以使其用作栈、队列、 或双端队列的方法。
getFirst();
element();
peek();
上面这3个方法都是返回list头元素,但是当list为空的时候,peek返回null,element()和peek()返回NoSuchElementElementException异常。
removeLast();
removeFirst();
remove();
poll();
上面这3个方法都是移除并返回列表的头,列表为空的时候,poll返回null,removeFirst()和remove()返回NoSuchElementElementException异常。
addFirst();
add();
offer();
addLast();
由此可以看出,LinkedList在插入删除操作更擅长。
14.Stack:
class Stack<T>{
private LinkedList<T> storage = new LinkedList<T>();
public void push(T t){
storage.addFirst(t);
}
public T peek(){
return storage.getFirst();
}
public T pop(){
return storage.removeFirst();
}
public boolean empty(){
return storage.isEmpty();
}
public String toString(){
return storage.toString();
}
}
上述代码才应该是Stack的具体实现,即通过LinkedList实现的。
注意:
在Java1.0的时候,设计者没有通过上述组合的方式来形成Stack(组合的好处是可以选定“方法集”,即不需要的方法我们就不声明),java.util.Stack它却是愚蠢的继承了Vector类,使得它拥有全部的Vector方法,再附加自己的方法,这样的设计是冗余且幼稚的。
结论:
当你想要使用Stack的时候,用LinkedList来实现功能。
15.Set:
set也是一个Collection, Collection通用方法它都拥有。
TreeSet将元素存储在红-黑树数据结构中。
HashSet使用的是散列函数(以后再探讨)。
Set最重要的功能就是查找和判断归属性。