Java编程思想读书笔记——持有对象

来源:互联网 发布:广告算法工程师招聘 编辑:程序博客网 时间:2024/05/17 17:41

第十一章 持有对象

集合类:对象类型为List、Set、Queue和Map的类型。

11.1 泛型和类型安全的容器

使用预定义的泛型容器可以保存特定类型的对象,无论存取都不必关心类型转换。

该类型的子类对象也可以通过向上转型,存入到泛型容器中。

11.2 基本概念

Java容器类可以划分成两类:Collection与Map
1) Collection:一个独立元素的队列,这些元素都服从一条或多条规则。这一类又可以分为List、Set和Queue三个分类。
2) Map:一组成对的键值对对象,允许使用键查找值,也被称为字典或者关联数组。

通常情况下,在创建一个具体类对象时,会将其向上转型成为对应的接口,如:

List<Apple> apples = new ArrayList<>();List<Apple> apples2 = new LinkedList<>();

但是如果需要使用到具体类的特有方法时,就无需向上转型,直接创建具体类对象即可。

Collection接口概括了序列的概念,而序列是一种存放一组对象的方式。该接口有add()方法,表示将一个新元素放置到Collection中。

11.3 添加一组元素

创建Collection对象的方式:
1) 直接创建实现Collection接口的具体类对象,如ArrayList等;

a) 可以不接受参数,然后使用for循环逐个元素添加,也可以使用addAll()方法,将一组元素直接添加;b) 可以接受一个Collection对象作为参数,将该Collection对象的中所有元素存入新创建的Collection对象中。

2) 使用其他方法

a) 使用Arrays.asList(),该方法接受一个数组或者可变参数列表,并将之转换为List对象,需要注意的是,此种方式获得的List对象,由于底层实现仍然是数组,在添加或者删除元素时会出现UnsupportedOperationException异常。b) 使用Collections.addAll(),这一方法可以接收一个Collection对象、一个数组或者是可变参数列表作为参数,得到新的Collection对象;c) 使用Collection.addAll(),这一方法与上一种不同的是,它只能接受Collection对象作为参数,灵活性受到限制。
package com.mzm.chapter11;import java.util.*;/** *  */public class AddingGroups {    public static void main(String[] args){        Collection<Integer> collection = new ArrayList<>(Arrays.asList(1, 2, 3, 4, 5));        Integer[] moreInts = {6, 7, 8, 9, 10};        collection.addAll(Arrays.asList(moreInts));        Collections.addAll(collection, 11, 12, 13, 14, 15);        Collections.addAll(collection, moreInts);        List<Integer> list = Arrays.asList(16, 17, 18, 19, 20);        list.set(1, 99);        //产生UnsupportedOperationException        //list.add(21);    }}

之后的显示类型参数说明可能在之后的JDK版本中被修正了,没有书中说的运行结果。

10.4 容器的打印

Collection的toString()方法,以”[“开头,以”]”结尾,每个元素之间用”,”分隔;
Map的toString()方法,以”[“开头,以”]”结尾,每一对键值对之间,以”,”分隔,针对每一对键值对,键在前,值在后,中间使用”=”分隔。

10.5 List

addAll(int index, List<T> subList):在List的索引为index的位置,插入subList的所有元素;contains(T t):判断某个对象是否在List中;remove(T t):移除某个对象;remove(int index):移除List中索引为index的元素;removeAll():移除List中的全部元素;indexOf(T t):获取某个对象在List中的索引;add(int index, T t):在List中间插入元素,该操作消耗性能;subList(int startIndex, int endIndex):获取子List,包头不包尾,本质是创建一个新的List;containsAll(List<T> subList):List中是否包含subList中的全部元素;retainAll(List<T> otherList):List与otherList的交集,注意该操作不创建新的List,而是在原来的List上,将不在otherList中的元素删除;set(int index, T t):将List中索引为index的元素设置为t;isEmpty():判断List长度是否为0;clear():将List的所有元素清空;toArray():将List转换为数组,注意是返回Object数组;toArray(T list.get(i)):将List转换为数组,但返回的是类型与List的类型参数相同的数组;

11.6 迭代器

不考虑容器类型,对容器插入元素并将它们再次取回。
迭代器是一个对象,它的工作是遍历并选择序列中的对象,而客户端程序员无需关心该序列的底层实现。
迭代器也被称为轻量级对象,因为其创建代价小。

Java中的Iterator,它只能单向移动,具有如下方法:

iterator():返回一个Iterator对象,它将准备好返回序列的第一个元素;next():返回序列的下一个元素;hasNext():判断序列是否含有下一个元素;remove():将迭代器新近返回的元素删除;

迭代器将遍历序列的操作与序列底层的结构分离,统一了对容器的访问方式。

11.6.1 ListIterator

ListIterator是Iterator的一个子类,只能用于各种List的访问。ListIterator可以双向移动,可以产生当前位置的前一个和后一个元素的索引,并且可以使用set()方法,将最近访问过的元素进行替换。此外,还可以通过listIterator(int index)的方法,获得一个一开始就指向index位置的ListIterator。

11.7 LinkedList

LinkedList的增删为O(1),对元素的随机访问为O(n);ArrayList的增删为O(n),对元素的随机访问为O(1)。

getFirst()/element()/peek():获取第一个元素,poll()在列表为空时返回null,另外两个抛出NoSuchElementException异常;  removeFirst()/remove()/poll():移除并返回第一个元素,差异与上面类似;addFirst()/add()/offer()/addLast():将某个元素添加的末尾;removeLast():移除并返回最后一个元素。

11.8 Stack

栈是指先进后出的容器,也被称为叠加栈,最典型的例子是自助餐托盘。
可以使用LinkedList来实现:

package com.mzm.chapter11;import java.util.LinkedList;/** *  */public class Stack<T> {    private LinkedList<T> storage = new LinkedList<>();    public void push(T v){        storage.addFirst(v);    }    public T peek(){        return storage.getFirst();    }    public T pop(){        return storage.removeFirst();    }    public boolean empty(){        return storage.isEmpty();    }    public String toString(){        return storage.toString();    }}

11.9 Set

Set不保存重复元素。
查找是Set最重要的操作,一般是使用HashSet。

HashSet、TreeSet和LinkedHashSet的区别在于,HashSet使用散列函数来维护元素的顺序,TreeSet是将元素存储在红黑树数据结构中,LinkedHashSet使用链表来维护元素的插入顺序。

方法包括:add()、addAll()、contains()、addAll()、containsAll()、remove()、removeAll()。

11.10 Map

Map是将对象映射到另一个对象。

11.11 Queue

队列是一个先进先出的容器。
LinkedList提供了方法以支持队列的行为,并且实现了Queue接口,所以可以使用Queue引用指向LinkedList对象。

11.11.1 PriorityQueue

队列规则:在给定一组队列中的元素的情况下,确定下一个弹出队列的元素的规则。
先进先出声明的是下一个元素应该是等待时间最长的元素。
优先级队列声明下一个弹出元素是最需要的元素(具有最高优先级)。
PriorityQueue在调用offer()方法插入元素时,默认是根据自然顺序排列的,可以传入自定义的Comparator来修改顺序。

package com.mzm.chapter11;import java.util.*;/** * Created by 蒙卓明 on 2017/10/14. */public class PriorityQueueDemo {    public static void main(String[] args){        //默认是升序排列        PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();        Random rand = new Random(47);        for(int i = 0; i < 10; i++){            priorityQueue.offer(rand.nextInt(i + 10));        }        QueueDemo.printQ(priorityQueue);        List<Integer> ints = Arrays.asList(25, 22, 20, 18, 14, 9, 3, 1, 1, 2, 3, 9, 14, 18, 21, 23, 25);        priorityQueue = new PriorityQueue<>(ints);        QueueDemo.printQ(priorityQueue);        //指定降序        priorityQueue = new PriorityQueue<>(ints.size(), Collections.reverseOrder());        priorityQueue.addAll(ints);        QueueDemo.printQ(priorityQueue);        String fact = "EDUCATION SHOULD ESCHEW OBFUSCATION";        List<String> strings = Arrays.asList(fact.split(""));        PriorityQueue<String> stringPQ = new PriorityQueue<>(strings);        QueueDemo.printQ(stringPQ);        //指定降序        stringPQ = new PriorityQueue<>(strings.size(), Collections.reverseOrder());        stringPQ.addAll(strings);        QueueDemo.printQ(stringPQ);        Set<Character> charSet = new HashSet<>();        for(char c : fact.toCharArray()){            charSet.add(c);        }        PriorityQueue<Character> characterPQ = new PriorityQueue<>();        QueueDemo.printQ(characterPQ);    }}

11.12 Collection和Iterator

如果要针对所有Collection类型提供共同的方法,最好是通过迭代器的方式。实现Collection接口,需要实现该接口的所有方法,较为麻烦,虽然AbstractCollection提供了Collection的默认实现,即使是继承该类,也必须提供迭代器的实现,何况已经继承了其他类的情况,所以最好是使用迭代器。

package com.mzm.chapter11;import java.util.*;/** * Iterator比Collection要好一些 *  */public class InterfaceVsIterator {    public static void display(Iterator<Pet> it){        while(it.hasNext()){            Pet p = it.next();            System.out.print(p.id() + ":" + p + " ");        }        System.out.println();    }    public static void display(Collection<Pet> pets){        for(Pet p : pets){            System.out.print(p.id() + ":" + p + " ");        }        System.out.println();    }    public static void main(String[] args){        List<Pet> petList = Pet.arrayList(8);        Set<Pet> petSet = new HashSet<>(petList);        Map<String, Pet> petMap = new LinkedHashMap<>();        String[] names = {"Ralph", "Eric", "Robin", "Lacey", "Britney", "Sam", "Spot", "Fluffy"};        for(int i = 0; i < 8; i++){            petMap.put(names[i], petList.get(i));        }        display(petList);        display(petSet);        display(petList.iterator());        display(petSet.iterator());        System.out.println(petMap);        System.out.println(petMap.keySet());        display(petMap.values());        display(petMap.values().iterator());    }}
package com.mzm.chapter11;import java.util.AbstractCollection;import java.util.Iterator;/** * AbstractCollection提供了Collection的默认实现,但即使继承该类,也同样要实现iterator()方法来提供迭代器 * 不如直接使用迭代器 *  */public class CollectionSequence extends AbstractCollection<Pet> {    private Pet[] pets = Pet.arrayList(8).toArray(new Pet[0]);    @Override    public Iterator<Pet> iterator() {        return new Iterator<Pet>() {            private int index = 0;            @Override            public boolean hasNext() {                return index < pets.length;            }            @Override            public Pet next() {                return pets[index++];            }            public void remove(){                throw new UnsupportedOperationException();            }        };    }    @Override    public int size() {        return pets.length;    }    public static void main(String[] args){        CollectionSequence c = new CollectionSequence();        InterfaceVsIterator.display(c);        InterfaceVsIterator.display(c.iterator());    }}
package com.mzm.chapter11;import java.util.Iterator;/** * 当这个类继承了其他类时,不能再继承AbstractCollection了 *  */public class NonCollectionSequence extends PetSequence{    public Iterator<Pet> iterator(){        return new Iterator<Pet>() {            private int index = 0;            @Override            public boolean hasNext() {                return index < pets.length;            }            @Override            public Pet next() {                return pets[index++];            }            public void remove(){                throw new UnsupportedOperationException();            }        };    }}class PetSequence{    protected Pet[] pets = Pet.arrayList(8).toArray(new Pet[0]);}

11.13 Foreach与迭代器

所有的Collection都能使用foreach语法遍历,因为其实现了Iterable接口,该接口包含一个能够产生Iterator的iterator()的方法。

注意数组没有实现Iterable接口。

11.13.1 适配器方法惯用法

如果需要在foreach中进行反序遍历,可以使用适配器设计模式。

package com.mzm.chapter11;import java.util.ArrayList;import java.util.Arrays;import java.util.Collection;import java.util.Iterator;/** * 使用适配器设计模式在foreach中添加反向遍历 *  */public class AdapterMethodIdiom {    public static void main(String[] args){        ReversibleArrayList<String> ral =                new ReversibleArrayList<>(Arrays.asList("To be or not to be".split(" ")));        //正向遍历        for(String s : ral){            System.out.print(s + " ");        }        System.out.println();        //反向遍历        for(String s : ral.reverse()){            System.out.print(s + " ");        }    }}class ReversibleArrayList<T> extends ArrayList<T>{    public ReversibleArrayList(Collection<T> c){        super(c);    }    public Iterable<T> reverse(){        return new Iterable<T>() {            @Override            public Iterator<T> iterator() {                return new Iterator<T>() {                    int current = size() - 1;                    @Override                    public boolean hasNext() {                        return current > -1;                    }                    @Override                    public T next() {                        return get(current--);                    }                    public void remove(){                        throw new UnsupportedOperationException();                    }                };            }        };    }}
原创粉丝点击