(1)HashSet无序的,查找元素最快;HashSet使用的是相当复杂的方式来存储元素的(p222),出于速度的原因,HashSet使用了散列。HashSet所维护的顺序与TreeSet或LinkedHashSet都不同,因为他们的实现具有不同的元素的存储方式。TreeSet将元素存储在红-黑树数据结构中,而HashSet使用的是散列函数,LinkedHashSet因查询速度的原因,也使用了散列,但是看起来它使用了链表来维护元素的插入顺序。
(2)TreeSet它按照比较结果的升序保存对象,保持元素处于排序状态;
(3)LinkedHashSet,它按照被添加的顺序保存对象,以插入顺序保存元素。
Map
1、Map也被称为关联数组,就像一个简单的数据库。
Map是一种将对象(而非数字)与对象相关联的设计。HashMap设计用来快速访问;而TreeMap保持“键”始终处于排序状态,所以没有HashMap快。LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问能力。
如何解释散列?(p245)
Map保存的顺序并不是他们插入的顺序;
HashMap也提供了最快的查找技术,无序保存,键和值在Map中的保存顺序并不是他们的插入顺序,因为HashMap实现使用的是一种非常快的算法来控制顺序;
TreeMap按照比较结果的升序保存键;
LinkedHashMap按插入顺序保存键,同时还保留了HashMap的查询速度。
Queue
1、Queue:队列是一个典型的先进先出(FIFO)的容器。即从容器的一端放入事物,从另一端取出,并且事物放入容器的顺序与取出的顺序是相同的。队列常被当作一种可靠的将对象从程序的某个区域传输到另一个区域的途径。
队列在并发编程中特别重要,因为他们可以安全地将对象从一个任务传输到另一个任务。
LinkedList提供了方法以支持队列的行为,并且它实现了Queue的接口,(p236)
各种Queue以及栈的行为,由LinkedList提供支持(p245)
public static void main(String[] args) {
Queue<Integer> queue = new LinkedList<Integer>();
Random rand = new Random(47);
for(int i=0; i<10; i++){
queue.offer(rand.nextInt(i + 10));//offer方法是一个元素插入到队尾或者返回false
}
while(queue.peek() != null){//peek获取栈顶第一元素,pop弹栈,push压栈
System.out.println(queue.remove() + " ");
}
}
2、先进先出描述了最典型的队列规则。队列规则是指在给定一组队列中的元素的情况下,确定下一个弹出队列的元素的规则。
先进先出声明的是下一个元素应该是等待时间最长的元素。
优先级队列声明下一个弹出元素是最需要的元素(具有最高的优先级)。(p237)
迭代
1、迭代器也是一种设计模式,迭代器通常被称为轻量级对象:创建它的代价小。(p226)
2、Java的Iterator只能单向移动
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<Integer, String>();
map.put(100, "jack");
map.put(200, "marry");
map.put(300, "sisi");
/* 1、Set迭代 */
System.out.println("******Set迭代******");
Set<Integer> set = new HashSet<Integer>();
Collections.addAll(set, 100,200,300);
Iterator<Integer> setIt = set.iterator();
while (setIt.hasNext()) {
Integer key = setIt.next();
System.out.print(key + "\t");
}
/* 2、Map迭代一:keySet */
System.out.println("\r\r******Map迭代:keySet******");
Set<Integer> keySet = map.keySet();// 将Map集合的Key转成Set集合,再通过key获取对应的值
Iterator<Integer> map1It = keySet.iterator();
while (map1It.hasNext()) {
Integer key = map1It.next();
String value = map.get(key);
System.out.print(key + "-" + value + "\t");
}
/* 3、Map迭代二:entrySet */
System.out.println("\r\r******Map迭代:entrySet******");
Set<Entry<Integer, String>> entrySet = map.entrySet();
Iterator<Entry<Integer, String>> it = entrySet.iterator();
while (it.hasNext()) {
Entry<Integer, String> entry = it.next();
Integer key = entry.getKey();
String value = entry.getValue();
System.out.print(key + "<->" + value + "\t");
}
/* 4、Map迭代三:增强for循环 */
System.out.println("\r\r******Map迭代:增强for循环******");
for(Integer key : map.keySet()){//注意这里Key的类型是由map的泛型决定,否则是object
System.out.print(key + ":" + map.get(key) + "\t");
}
/* 5、增强for循环迭代List */
List<Department> newDeptList = new ArrayList<Department>();
List<String> deptName = new ArrayList<String>();
for(Department dept:deptList){
if(!deptName.contains(dept.getDepartmentName())){
deptName.add(dept.getDepartmentName());
newDeptList.add(dept);
}
}
}
输出结果:
3 、ListIterator
ListIterator是一个更加强大的Iterator的子类型,是一个接口,它只能用于各种List类的访问。Iterator只能向前移动,但是ListIterator可以双向移动。它还可以产生相对于迭代器在列表中指向的当前位置的前一个和后一个元素的索引,并且可以使用set()方法替换它访问过的最后一个元素。你可以通过调用listIterator()方法产生一个指向List开始处的ListIterator,并且还可以通过调用listIterator(n)方法创建一个一开始就指向列表索引为n的元素处的ListIterator。
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
Collections.addAll(list, "java","c","c++","oracle","mysql");
ListIterator<String> it = list.listIterator();
while(it.hasNext()){
System.out.println(it.next() + " " + it.nextIndex() + ", " + it.previousIndex() + ";");
}
System.out.println();
//Backwards
while(it.hasPrevious()){
System.out.print(it.previous() + " ");//previous前一个元素
}
}
另外还可以通过ListIterator实现动态向List中添加数据
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
Collections.addAll(list, "jack","marry","sisi");
/* 1、使用iterator动态添加数据 */
Iterator<String> it = list.iterator();
while(it.hasNext()){
String key = it.next();//这行在第二次循环时会出错,因为在创建迭代器的时候(it = list.iterator()),list通知迭代器的是长度为3,而在执行完list.add(“qq”)时,list长度已经是4,但是没有及时通知迭代器,所以会出错。
System.out.print(key+"\t");
// list.add("qq");//迭代时向List集合中添加数据,在第一次循环最后会想list中添加数据,在验证iterator动态添加数据时需吧这行注释去掉
}
System.out.println("\r**************************");
/* 2、使用ListIterator动态添加数据 */
ListIterator<String> it2 = list.listIterator();//ListIterator
while (it2.hasNext()) {
String key = it2.next();
System.out.print(key + "\t");
// 动态通知迭代器,加入了新元素,从而迭代器自动通知List集合。
it2.add("qq");//现在添加进去的数据,在下次迭代时才会被迭代出来
}
System.out.println("\r**************************");
/* 3、再次对集合迭代,验证数据是否被添加进去 */
ListIterator<String> it3 = list.listIterator();
while (it3.hasNext()) {
String key = it3.next();
System.out.print(key + "\t");
}
}
输出结果:
三、 总结
1、新程序中不应该使用过时的Vector、Hashtable 和Stack。(p245)
2、Java容器简图(p246)
3、程序的输出是从Object默认的toString()方法产生的,该方法将打印类名,后面跟随该对象的散列码的无符号十六进制表示(这个散列码是通过hashCode()方法产生的)。你将在第17章中了解到有关散列码的内容(p218)
4、优化是一个很棘手的问题,最好的策略就是置之不顾,直到你发现需要担心它了(尽管理解这些问题总是一种好的思路)
5、通过针对接口而非具体实现来编码,我们的代码可以应用与更多的对象类型。(p239)
6、将保持不变的事物与会发生改变的事物相分离
7、Collections常用方法(不包括Object继承而来的方法),下列方法也是可通过Set或List执行的所有操作(List还有额外的功能),Map不是继承自Collection会另行介绍。
|
|