《JAVA编程思想》学习笔记---第十一章:持有对象

1,泛型和泛型安全的容器

根据多态,集合类如果不使用泛型就会装任何类,因为所有类都是Object的子类,所以一个集合类的实例是可以装不同类的实例的。不过在取出这些实例时必须强制类型转换,不然会在编译时报错!看如下实例:

package com.csdn.abc;

import java.util.ArrayList;

public class First {

    @SuppressWarnings("unchecked")
    public static void main(String[] args){
        ArrayList apples = new ArrayList();
        for(int i = 0; i < 3; i++){
            apples.add(new Apple());
        }
        apples.add(new Orange());
        for(int i = 0; i < apples.size(); i++){
            System.out.println(((Apple) apples.get(i)).id());
        }
    }

}

class Apple{

    private static long counter;
    private final long id = counter++;

    public long id(){
        return id;
    }
}

class Orange{

}

ArrayList的实例能同时装Apple与Orange的实例,因为它们都是Object的子类。
运行实例,输出:

0
1
2
Exception in thread "main" java.lang.ClassCastException: com.Orange cannot be cast to com.Apple
    at com.First.main(First.java:15)

把Orange类型强制转为Apple类型会在运行时报错。

为了避免这种错误,需要使用泛型规定集合类中存放的数据类型,避免出现不同的类型!
把上面的ArrayList apples = new ArrayList();
改为 ArrayList apples = new ArrayList();

这样当往apples中存放Oranle类型的实例就会报错,这是报错就是编译时报错,而不是运行时报错。
运用泛型后,取出元素时,强制类型转换就不需要了!

2,基本概念

集合类分为两种
(1)Collection
包括List(按照插入顺序保存数据,按照索引查找元素,可理解为长度可变的数组),Set(不能有重复元素),Queue(队列)。
(2)Map
以键值对的形式存在。
实例:

package com;

import java.util.ArrayList;
import java.util.Collection;

public class Two {

    public static void main(String[] args) {
        Collection c = new ArrayList();
        for(int i = 0; i < 10; i++){
            c.add(i);
        }
        for(Integer i:c){
            System.out.print(i+",  ");
        }
    }

}

add()方法把元素添加进集合,List的add()方法总是将元素添加进集合,但对于Set来说,add()方法不一定会添加元素,因为Set集合不允许重复,所以Set在添加前要检查是否有重复值。

所有的Collection都可以用foreach遍历,另外们还有“迭代器”可以更灵活的遍历集合。

3,添加一组元素

在一个Collection中添加一组元素有两种方法
方法一:Arrays.asList()方法接受一个用逗号分隔的元素列表(即可变参数),然后将其转换为List对象:

package com;

import java.util.Arrays;
import java.util.List;

public class Three {

    public static void main(String[] args) {
        List list = Arrays.asList(1,2,3);
        for(int i:list){
            System.out.print(i+", ");//输出1, 2, 3,
        }
    }

}

这种方法生成的集合只是像集合,其实不是集合,而是一个数组,不能对其进行添加和删除!

方法二:new Collection().addAll()方法接受一个集合,将此集合添加到Collection中:

package com;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

public class Four {

    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(0);
        List list = Arrays.asList(1,2,3);
        collection.addAll(list);
        for(int i:collection){
            System.out.print(i+", ");//输出0, 1, 2, 3,
        }
    }

}

方法三:Collections.addAll()方法接受一个集合对象和一个用逗号分隔的列表:

package com;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;

public class Five {

    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(0);
        Collections.addAll(collection,1,2,3,4);
        for(int i:collection){
            System.out.print(i+", ");//输出0, 1, 2, 3, 4,
        }
    }

}

在第四版的《java编程思想》中,这三种方法除了能添加一组参数,还能添加一个集合,但是我用的java8不支持添加集合!!!
书有点老了,没钱买第五版,第五版全是正版的!!!

书中下面代码:

package com;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class Six {

    public static void main(String[] args) {
        List snow1 = Arrays.asList(new Crusty(),new Slush(),new Powder());
        List snow2 = Arrays.asList(new Light(),new Heavy());
        List snow3 = new ArrayList();
        Collections.addAll(snow3,new Light(),new Heavy());
        List snow4 = Arrays.asList(new Light(),new Heavy());
    }

}

class Snow{}
class Powder extends Snow{}
class Light extends Powder{}
class Heavy extends Powder{}
class Crusty extends Snow{}
class Slush extends Snow{}

按书中所说,snow2变量会报错,因为 Arrays.asList(new Light(),new Heavy()) 返回的是 List ,而不是 List
但我亲测,不会报错!!!
编译器在不断进步啊!!!

4,集合的打印

先看例子:

package com;

import java.util.*;

public class Seven {

    public static void main(String[] args) {
        System.out.println(fill(new ArrayList()));
        System.out.println(fill(new LinkedList()));
        System.out.println(fill(new HashSet()));
        System.out.println(fill(new TreeSet()));
        System.out.println(fill(new LinkedHashSet()));
        System.out.println(fill(new HashMap()));
        System.out.println(fill(new TreeMap()));
        System.out.println(fill(new LinkedHashMap()));
    }

    static Collection fill(Collection collection){
        collection.add("rat");
        collection.add("cat");
        collection.add("dog");
        collection.add("dog");
        return collection;
    }

    static Map fill(Map map){
        map.put("rat","Fuzzy");
        map.put("cat","Rags");
        map.put("dog","Bosco");
        map.put("dog","sqot");
        return map;
    }

}
/*
输出:
[rat, cat, dog, dog]
[rat, cat, dog, dog]
[rat, cat, dog]
[cat, dog, rat]
[rat, cat, dog]
{rat=Fuzzy, cat=Rags, dog=sqot}
{cat=Rags, dog=sqot, rat=Fuzzy}
{rat=Fuzzy, cat=Rags, dog=sqot}
*/

从中可以看出,set不允许重复,map的键不允许重复,带Tree字符串的类还将元素进行了排序!!!

5,List

写代码学习集合方法:

package com;

import java.util.*;

public class Eight {

    public static void main(String[] args) {
        List list = new ArrayList();
        Collections.addAll(list,new A(),new B(),new C(),new D());
        //打印集合
        System.out.println("1:"+list);
        //add()方法添加元素
        E e = new E();
        list.add(e);
        System.out.println("2:"+list);
        //contains()方法判断元素是否在集合中
        System.out.println("3:"+list.contains(e));
        //remove()方法删除元素
        list.remove(e);
        //get()方法根据索引返回元素
        Word word = list.get(1);
        //indexOf()方法根据元素返回索引
        System.out.println("4:元素为:"+word+"  索引为:"+list.indexOf(word));
        Word b = new B();
        //虽然list中有B类的对象,但list中的B的对象与上一行的b并不是同一对象
        //所以下面将返回-1,b并且删除不会成功
        System.out.println("5:"+list.indexOf(b));
        System.out.println("6:"+list.remove(b));
        //因为word是根据索引取出的,所以删除成功
        System.out.println("7:"+list.remove(word));
        System.out.println("8:"+list);
        //根据索引添加元素
        list.add(1,new E());
        System.out.println("9:"+list);
        List list2 = new ArrayList();
        Collections.addAll(list2,new A(),new C());
        System.out.println("10:"+list2);
        //containAll()方法判断集合是否包含另一个集合
        System.out.println("11:"+list.containsAll(list2));

        List copy = new ArrayList(list);
        list2 = Arrays.asList(list.get(1),list.get(3));
        System.out.println("12:"+list2);
        //retainAll()方法取交集并添加到调用的对象中
        copy.retainAll(list2);
        System.out.println("13:"+copy);
        copy = new ArrayList(list);
        System.out.println("14:"+copy);
        //根据索引删除
        copy.remove(1);
        System.out.println("15:"+copy);
        //removeAll()方法从copy中删除list2中的所有元素
        copy.removeAll(list2);
        System.out.println("16:"+copy);
        //根据索引线删除再添加,即修改
        copy.set(1,new B());
        System.out.println("17:"+copy);
        //指定索引添加集合
        copy.addAll(0,list2);
        System.out.println("18:"+copy);
        //isEmpty()方法判断是否为空
        System.out.println("19:"+ list.isEmpty());
        //toArray()方法将集合转为数组,无参数返回Object
        Object[] o = list.toArray();
        System.out.println("20:"+o[1]);
        //返回Word类型的数组
        Word[] o1 = list.toArray(new Word[0]);
        System.out.println("21:"+o1[1]);
        //cleat()方法清空集合
        list.clear();
        System.out.println("22:"+ list);
    }

}

class Word{}
class A extends Word{}
class B extends Word{}
class C extends Word{}
class D extends Word{}
class E extends Word{}
/*
输出:
1:[com.A@1db9742, com.B@106d69c, com.C@52e922, com.D@25154f]
2:[com.A@1db9742, com.B@106d69c, com.C@52e922, com.D@25154f, com.E@10dea4e]
3:true
4:元素为:com.B@106d69c  索引为:1
5:-1
6:false
7:true
8:[com.A@1db9742, com.C@52e922, com.D@25154f]
9:[com.A@1db9742, com.E@647e05, com.C@52e922, com.D@25154f]
10:[com.A@1909752, com.C@1f96302]
11:false
12:[com.E@647e05, com.D@25154f]
13:[com.E@647e05, com.D@25154f]
14:[com.A@1db9742, com.E@647e05, com.C@52e922, com.D@25154f]
15:[com.A@1db9742, com.C@52e922, com.D@25154f]
16:[com.A@1db9742, com.C@52e922]
17:[com.A@1db9742, com.B@14eac69]
18:[com.E@647e05, com.D@25154f, com.A@1db9742, com.B@14eac69]
19:false
20:com.E@647e05
21:com.E@647e05
22:[]
*/

6,迭代器

迭代器用于遍历集合元素,比foreach语法更为灵活!看代码:

package com;

import java.util.*;

public class Nine {

    public static void main(String[] args) {
        Collection collection = new ArrayList();
        collection.add(0);
        Collections.addAll(collection,1,2,3,4,5,6,7,8);
        //iterator()方法生成一个迭代器对象
        Iterator it = collection.iterator();
        //hasNext()方法判断是否还有下一个元素
        while(it.hasNext()){
            //next()方法取出下一个元素
            int sum = it.next();
            System.out.print(sum+", ");
        }
        System.out.println();
        for(int i:collection){
            System.out.print(i+", ");
        }
        it = collection.iterator();
        System.out.println();
        for(int i = 0; i < 3; i++){
            it.next();
            it.remove();
        }
        System.out.println(collection);
    }

}
/*输出:
0, 1, 2, 3, 4, 5, 6, 7, 8, 
0, 1, 2, 3, 4, 5, 6, 7, 8, 
[3, 4, 5, 6, 7, 8]

*/

当迭代器遍历到最后并不会重新 ,所以想再次使用,必须再次调用iterator()方法

package com;

import java.util.*;

public class Ten {

    public static void main(String[] args) {
        Collection collection = new ArrayList();
        Collections.addAll(collection,0,1,2,3,4,5,6,7,8);
        LinkedList linkedList = new LinkedList(collection);
        HashSet hashSet = new HashSet(collection);
        TreeSet treeSet = new TreeSet(collection);
        display(collection.iterator());
        display(linkedList.iterator());
        display(hashSet.iterator());
        display(treeSet.iterator());
    }

    public static void display(Iterator it){
        while(it.hasNext()){
            int sum = it.next();
            System.out.print(sum+", ");
        }
        System.out.println();
    }

}
/*
输出:
0, 1, 2, 3, 4, 5, 6, 7, 8, 
0, 1, 2, 3, 4, 5, 6, 7, 8, 
0, 1, 2, 3, 4, 5, 6, 7, 8, 
0, 1, 2, 3, 4, 5, 6, 7, 8, 

*/

iterator()只能向前遍历,而不能想后遍历。使用listIterator()方法能够实现向后遍历:

package com;

import java.util.*;

public class ListIteratorDemo {

    public static void main(String[] args) {
        ArrayList collection = new ArrayList();
        collection.add(0);
        Collections.addAll(collection,1,2,3,4);
        ListIterator it =  collection.listIterator();
        while(it.hasNext()){
            System.out.print(it.next()+","+it.nextIndex()+","+it.previousIndex()+";");
        }
        System.out.println();
        while(it.hasPrevious()){
            System.out.print(it.previous()+",");
        }
        System.out.println();
        System.out.print(collection);
        it = collection.listIterator(2);
        while(it.hasNext()){
            it.next();
            it.set(5);
        }
        System.out.println(collection);
    }
}
/*
输出:
0,1,0;1,2,1;2,3,2;3,4,3;4,5,4;
4,3,2,1,0,
[0, 1, 2, 3, 4][0, 1, 5, 5, 5]
*/

7,LinkedList

一些方法的使用:

package com;

import java.util.*;

public class LinkedListFeatures {

    public static void main(String[] args) {
        ArrayList collection = new ArrayList();
        collection.add(0);
        Collections.addAll(collection,1,2,3,4,5,6,7);
        LinkedList linked = new LinkedList(collection);
        System.out.println(linked);
        //getFirst()与element()与peek()方法都返回集合的第一个元素
        System.out.println(linked.getFirst());
        System.out.println(linked.element());
        System.out.println(linked.peek());
        System.out.println(linked.remove());
        System.out.println(linked.removeFirst());
        System.out.println(linked);
        linked.addFirst(8);
        System.out.println(linked);
        linked.addLast(9);
        System.out.println(linked);
        linked.removeLast();
        System.out.println(linked);
    }

}

Stack

使用LinkedList实现栈的功能,先定义一个栈类:

package com;

import java.util.*;

public class Stack {

    private LinkedList 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();
    }
}

测试类

package com;

public class StackTest {

    public static void main(String[] args) {
        Stack stack = new Stack();
        for(String s:"my dog has fleas".split(" ")){
            stack.push(s);
        }
        while(!stack.empty()){
            System.out.println(stack.pop()+" ");
        }
    }

}

java API中本来就有Stack类,但是设计欠佳,多以用LinkedList这种方式代替原本的Stack更好!

9,Set

Set集合不允许有重复的元素,Set最常用的就是测试归属性,可以很容易的询问某个对象是否在某个Set中。正因如此,查找就成了Set最重要的操作。
存放Integer对象的HashSet示例:

package com;

import java.util.*;

public class SetOfInteger {

    public static void main(String[] args) {
        Random rand = new Random(47);
        Set intset = new HashSet();
        for(int i = 0;i < 10000; i++){
            intset.add(rand.nextInt(30));
        }
        System.out.println(intset);
    }

}
/*
输出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
*/

关于为何Set集合遍历后是有序的问题,这里我百度了一下,在知乎找到了答案:
实现是会变的,HashSet的迭代器在输出时“不保证有序”,但也不是“保证无序”。也就是说,输出时有序也是允许的,但是你的程序不应该依赖这一点。

TreeSet会将集合内的对象就行排序

Set最常见的操作就是使用contains()测试Set的归属性,下面是Set方法的一些示例:

package com;

import java.util.*;

public class SetOperations {

    public static void main(String[] args) {
        Set set1 = new HashSet();
        Collections.addAll(set1,"A,B,C,D,E,F,G,H,I,J,K,L".split(","));
        set1.add("M");
        //contains()方法测试集合中是否包含元素
        System.out.println("H:"+set1.contains("H"));
        System.out.println("N:"+set1.contains("N"));
        Set set2 = new HashSet();
        Collections.addAll(set2,"H,I,J,K".split(","));
        //containsAll()方法测试集合中是否包含另一个元素
        System.out.println(set1.containsAll(set2));
        set1.remove("H");
        System.out.println(set1.containsAll(set2));
        set1.removeAll(set2);
        System.out.println(set1);
    }

}

10,Map

package com;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

public class Statistics {

    public static void main(String[] args) {
        Random rand = new Random(47);
        Map<Integer,Integer> m = new HashMap<Integer,Integer>();
        for(int i = 0; i < 10000;i++){
            int r = rand.nextInt(20);
            Integer freq = m.get(r);
            m.put(r, freq == null?1:freq+1);
        }
        System.out.println(m);
    }

}
/*
输出:
{0=481, 1=502, 2=489, 3=508, 4=481, 5=503, 6=519, 7=471, 8=468, 9=549, 10=513, 11=531, 12=521, 13=506, 14=477, 15=497, 16=533, 17=509, 18=478, 19=464}
*/

实例中键是1-20,值则是10000次中,键出现的次数

11,Queue

LinkedList提供了方法以支持队列的行为,并且他实现了Queue接口,可以通过Linked向上转型为Queue,下列实例使用了Queue

package com;

import java.util.*;

public class QueueDemo {

    public static void printQ(Queue queue){
        //peek()方法返回队列的队首
        while(queue.peek()!=null){
            System.out.print(queue.remove()+" ");
        }
        System.out.println();
    }
    public static void main(String[] args) {
        Queue queue = new LinkedList();
        Random rand = new Random(47);
        //offer()方法将元素添加到队尾
        for(int i = 0; i< 10;i++){
            queue.offer(rand.nextInt(i+10));
        }
        printQ(queue);
        Queue qc = new LinkedList();
        for(char c:"Brontosaurus".toCharArray()){
            qc.offer(c);
        }
        printQ(qc);
    }

}

11.1,PriorityQueue

当使用PriorityQueue插入对象时,这个对象会在队列中排序!
看实例:

package com;

import java.util.*;

public class PriorityQueueDemo {

    public static void main(String[] args) {
        PriorityQueue 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 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 = "EDUCATTION SHOULD ESCHEW OBFUSCATION";
        List strings = Arrays.asList(fact.split(" "));
        PriorityQueue stringPQ = new PriorityQueue(strings);
        QueueDemo.printQ(stringPQ);

        stringPQ = new PriorityQueue(strings.size(),Collections.reverseOrder());
        stringPQ.addAll(strings);
        QueueDemo.printQ(stringPQ);

        Set charSet = new HashSet();
        for(char c:fact.toCharArray()){
            charSet.add(c);
        }
        PriorityQueue charcterPQ = new PriorityQueue(charSet);
        QueueDemo.printQ(charcterPQ);
    }

}

PriorityQueue有两个构造器,一个是构造器是直接添加集合,另一个是给出队列长度!
Collections.reverseOrder()代表了反序!
PriorityQueue会对队列就行排序!
最后一个Set元素用于将字母去重。

12,Collection和Iterator

package com;
import java.util.*;

public class InterfaceVsIterator {

    public static void display(Iterator ints){
        while(ints.hasNext()){
            int i = ints.next();
            System.out.print(i+" ");
        }
        System.out.println();
    }

    public static void display(Collection col){
        for(int i:col){
            System.out.print(i+" ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        List list = Arrays.asList(25,22,20,18);
        Set set = new HashSet<>(list);
        Map map = new LinkedHashMap();
        String[] name = "a b c d".split(" ");
        for(int i = 0; i < name.length; i++){
            map.put(name[i], list.get(i));
        }
        display(list);
        display(set);
        display(list.iterator());
        display(set.iterator());
        System.out.println(map);
        System.out.println(map.keySet());
        display(map.values());
        display(map.values().iterator());
    }

}

迭代器和foreach都可以遍历集合!

如果继承Collection接口就必须在子类中实现很多方法!
通过集成Collection的一个抽象类AbstractCollection可以避免实现过多的方法,不过需要实现iterator()方法!

package com;

import java.util.*;

public class CollectionSequence extends AbstractCollection {

    private Integer[] ints = {1,2,3,4};
    @Override
    public Iterator iterator() {
        return new Iterator(){
            private int index = 0;
            @Override
            public boolean hasNext() {
                return index < ints.length;
            }

            @Override
            public Integer next() {
                return ints[index++];
            }

            public void remove(){
                throw new UnsupportedOperationException();
            }
        };
    }

    @Override
    public int size() {
        return ints.length;
    }

    public static void main(String[] args){
        CollectionSequence c = new CollectionSequence();
        InterfaceVsIterator.display(c);
        InterfaceVsIterator.display(c.iterator());
    }

}

CollectionSequence类会根据iterator()方法判断集合中包含是哪个数组!
有点不懂!百度了一下,得知:foreach内部也是采用了Iterator的方式实现,只不过Java编译器帮我们生成了这些代码。
恩,懂了

下面实例不需要集成AbstractCollection但需要使用itreator()遍历,itreator()自己实现!

package com;

import java.util.*;

class IntSequence{
    protected int[] ints = {1,2,3,4};
}

public class NonCollectionSequence extends IntSequence{

    public Iterator iterator(){
        return new Iterator(){
            private int index = 0;
            @Override
            public boolean hasNext() {
                return index < ints.length;
            }

            @Override
            public Integer next() {
                return ints[index++];
            }

            public void remove(){
                throw new UnsupportedOperationException();
            }
        };
    }

    public static void main(String[] args) {
        NonCollectionSequence n = new NonCollectionSequence();
        InterfaceVsIterator.display(n.iterator());
    }

}

13,Foreach与迭代器

package com;

import java.util.*;

public class ForEachCollection {

    public static void main(String[] args) {
        Collection cs = new LinkedList();
        Collections.addAll(cs,"Take me Long way home".split(" "));
        for(String s : cs){
            System.out.print(s+" ");
        }
    }

}

Iterable接口被foreach用来在序列中移动
代码和12节示例一样

打印环境变量:

package com;

import java.util.*;

public class EnvironmentVariables {

    public static void main(String[] args) {
        for(Map.Entry entry:System.getenv().entrySet()){
            System.out.println(entry.getKey()+":"+entry.getValue());
        }
    }

}

foreach可以用于数组和任何其他Iterable.
但是数组不是Iterable!看如下实例;

package com;

import java.util.Arrays;

public class ArrayIsNotIterable {

    static  void test(Iterable id){
        for(T t : id){
            System.out.print(t+" ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        test(Arrays.asList(1,2,3));
        String[] strings = {"A","B","C"};
        //下面会报错
        //test(strings);
        for(String s : strings){
            System.out.print(s+" ");
        }
        System.out.println();
        test(Arrays.asList(strings));
    }

}

13.1,适配器方法习惯用法

适配器方法模式有点不懂!,不过没问题,理解下面代码还是可以的。

下面代码实现了反向迭代!需要添加一个能够产生Iterable对象的方法,该对象用于foreach语句,

package com;

import java.util.*;

public class AdapterMethodIdiom {

    public static void main(String[] args) {
        ReversibleArrayList 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.reversed()){
            System.out.print(s+" ");
        }
    }

}
class ReversibleArrayList extends ArrayList{
    public ReversibleArrayList(Collection c){
        super(c);
    }
    public Iterable reversed(){
        return new Iterable(){
            @Override
            public Iterator iterator() {
                return new Iterator(){

                    private int current = size()-1;

                    public boolean hasNext(){
                        return current > -1;
                    }

                    public T next(){
                        return get(current--);
                    }

                    public void remove(){
                        throw new UnsupportedOperationException();
                    }

                };
            }
        };
    }
}

这里先实现了返回Iterable对象的方法,在返回的对象中,重写了iterator()方法,使得反向迭代的逻辑可以实现!

在foreach语句的for(String s:ral.reversed())
调用反向迭代的方法可见,只要冒号后面的语句返回的对象中实现iterator方法就可以使用foreach!foreach会自动调用iterator()

下列代码实现了一个类实现三种不同的foreach迭代方法

package com;

import java.util.*;

public class MultiIterableClass implements Iterable{
    private String[] words = {"abc","def","ghi","jkl","mn"};

    public Iterator iterator() {
        return new Iterator(){
            private int index = 0;
            @Override
            public boolean hasNext() {
                return index < words.length;
            }

            @Override
            public String next() {
                return words[index++];
            }

            public void remove(){
                throw new UnsupportedOperationException();
            }
        };
    }

    public Iterable reversed(){
        return new Iterable(){

            @Override
            public Iterator iterator() {
                return new Iterator(){

                    private int current = words.length - 1;

                    public boolean hasNext(){
                        return current > -1;
                    }

                    public String next(){
                        return words[current--];
                    }

                    public void remove(){
                        throw new UnsupportedOperationException();
                    }

                };
            }
        };
    }

    public Iterable randomized(){
        return new Iterable(){
            public Iterator iterator(){
                List shuffled = new ArrayList<>(Arrays.asList(words));
                Collections.shuffle(shuffled,new Random(47));
                return shuffled.iterator();
            }
        };
    }

    public static void main(String[] args){
        MultiIterableClass mu = new MultiIterableClass();
        for(String s : mu.reversed()){
            System.out.print(s+" ");
        }
        System.out.println();
        for(String s : mu.randomized()){
            System.out.print(s+" ");
        }
        System.out.println();
        for(String s : mu){
            System.out.print(s+" ");
        }
    }
}
/*
输出:
mn jkl ghi def abc 
ghi abc mn def jkl 
abc def ghi jkl mn 
*/

Collections.shuffle()方法打乱了集合中的引用。
因为randomized()方法将一个ArrayList将Arrays.asList()方法的结果包装了起来,所以words没有被打乱,但如果没有用ArrayList包装,words将会被打乱!如下实例:

package com;

import java.util.*;

public class ModifyingArrayAsList {

    public static void main(String[] args) {
        Random rand = new Random(47);
        Integer[] ia = {1,2,3,4,5,6,7,8};
        List list = new ArrayList<>(Arrays.asList(ia));
        System.out.println(list);
        Collections.shuffle(list,rand);
        System.out.println(list);
        System.out.println(Arrays.toString(ia));
        System.out.println("------");
        List list2 = Arrays.asList(ia);
        System.out.println(list2);
        Collections.shuffle(list2,rand);
        System.out.println(list2);
        System.out.println(Arrays.toString(ia));
    }

}
/*
输出:
[1, 2, 3, 4, 5, 6, 7, 8]
[5, 4, 7, 1, 8, 2, 3, 6]
[1, 2, 3, 4, 5, 6, 7, 8]
------
[1, 2, 3, 4, 5, 6, 7, 8]
[7, 3, 1, 5, 8, 2, 6, 4]
[7, 3, 1, 5, 8, 2, 6, 4]
*/

14,总结

贴一张图表示集合之间的关系:
《JAVA编程思想》学习笔记---第十一章:持有对象_第1张图片

你可能感兴趣的:(java编程思想)