【Java编程思想】读书笔记(二)第十一章---第十五章

版权声明:整理不易,转载请注明出处。 https://blog.csdn.net/linmengmeng_1314/article/details/85472181

第十一章 持有对象

容器类的基本类型:ListSetQueueMap。这些对象类型也成为集合类,或容器。

Set对于每个对象只保存一次,Map是允许你讲某些对象与其他一些对象关联起来的关联数组,Java容器类都可以自动调整自身的尺寸。

11.1 泛型和类型安全的容器

当需要一个Apple对象的容器,我们使用最基本最可靠的容器ArrayList。ArrayList可以被当做“可以自动扩充自身尺寸的数组”来看待。

使用ArrayList:创建一个实例,用add()插入对象,然后用get()访问这些对象,此时需要使用索引,就像数组一样,但是不需要方括号。ArrayList还有一个size()方法,可以知道有多少元素添加进来了。

class Apple{
    private static long counter;
    private final long id = counter++;
    public long id(){
        return id;
    }
}

class Orange{}

public class ApplesAndOrangesWithoutGenerics {
    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());
        long id;
        for(int i = 0; i < apples.size(); i++){
            id = ((Apple) apples.get(i)).id();
            System.out.println(id);
        }
    }
}
// Output:0 1 2
// 去掉注解,会报错,提示不能将Orange对象转为Apple对象

ArrayList保存的是一个Object。所以可以将Orange和Apple放入同一个容器,但是在取出的时候,需要先将ArrayList内的Object对象向下转型为原始类型,然后调用方法id()。

为了防止这种ArrayList取值时,发生异常转换的问题,我们可以在创建ArrayList对象时限定其对象格式,即预定义泛型,定义用来保存Apple对象的ArrayList,可以声明:ArrayList<Apple> apples = new ArrayList<>();,而不仅仅是ArrayList,其中尖括号括起来的是类型参数(可以有多个),它制定了这个容器实例可以保存的类型。通过使用泛型,可以防止在编译期将错误类型的对象放入到容器中。

public class ApplesAndOrangesWithoutGenerics {
    public static void main(String[] args) {
        ArrayList<Apple> apples = new ArrayList<Apple>();
        for (int i = 0; i < 3; i++){
            apples.add(new Apple());
        }
        // Compire-time error
        //apples.add(new Orange());
        for(Apple apple : apples){
            System.out.println(apple.id());
        }
    }
}

此刻可以发现:在将元素从List中取出时,类型转换也不再是必须的了。因为List知道它保存的是什么类型,因此它会在调用get()时,替你执行转型。

当你指定了某个类型作为泛型参数时,你并不仅限于只能将确切类型的对象放置到容器中,向上转型也可以像作用于其他类型一样作用于泛型:

class Fuji extends Apple{}

然后在apples里面添加Fuji对象,也是允许的,最后使用foreach语法循环取出方法仍然不变

apples.add(new Fuji());

当一个对象里没有重写toString()方法时,直接打印该对象时,输出的为:Apple@4554617c
程序默认输出的是从Object默认的toString()方法产生的,该方法将打印类名,后面跟随该对象的散列码的无符号十六进制表示(这个散列码是通过hashCode()方法产生的)。

练习1:创建一个Gerbil(沙鼠),包含int gerbilNumber,在构造器中初始化它。添加一个方法hop(),用以打印沙鼠的号码以及它正在跳跃的信息。创建一个ArrayList,并向其中添加一串Gerbil对象。使用get()遍历List,并且对每个Gerbil调用hop().

class Gerbil{
    private final int gerbilNumber;
    Gerbil(int gerbilNumber){
        this.gerbilNumber = gerbilNumber;
    }

    @Override
    public String toString() {
        return "gerbil " + gerbilNumber;
    }

    public void hop(){
        System.out.println(this + " is hopping!");
    }
}

public class E01_Gerbil {
    public static void main(String[] args) {
        ArrayList<Gerbil> gerbils = new ArrayList<>();
        for (int i = 0; i < 10; i++){
            gerbils.add(new Gerbil(i));
        }
        for (Gerbil gerbil: gerbils) {
            gerbil.hop();
        }
    }
}

11.2 基本概念

Java的容器类库的用途是“保存对象”,并将其划分为两个不同的概念:

  1. Collection:一个独立元素的序列,这些元素都服从一条或多条规则。List必须按照插入的顺序保存元素,而Set不能有重复的元素。Queue按照排队规则来确定对象产生的顺序(通常与它们被插入的顺序相同)。
  2. Map: 一组成对的“键值对”对象,允许你使用键来查找值。ArrayList允许你使用数字来查找值,因此某种意义上讲,它将数字与对象关联在了一起。映射表允许我们使用另一个对象来查找某个对象,它也被称为“关联数组”或者“字典”。

在创建的时候如果你决定去修改你的实现,就需要在创建时修改,如:ArrayList<Apple> apples = new ArrayList<Apple>(); 因此,应该创建一个具体的对象,将其转型为对应的接口,然后在其余的代码中都是用这个接口。

但是也有例外,例如,LinkedList具有在List接口中未包含的额外的方法,而TreeMap也具有在Map接口中未包含的方法。如果需要使用这些方法,就不能将它们向上转型为通用的接口。

11.3 添加一组元素(Arrays.asList(),Collections.addAll(), Arrays.addAll())

在java.util包中的Arrays和Collections类中都有很多使用的方法,可以在一个Collection中添加一组元素。Arrays.asList()方法可以接受一个数组或者是一个用逗号隔开的元素列表(使用可变参数),并将其转换为一个List对象。Collections.addAll()方法接受一个Collection对象,以及一个数组或是一个用逗号分隔的列表,将元素添加到Collection中。

public class AddingGroups {
    public static void main(String[] args) {
        Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));
        Integer[] moreInts = {6,7,8,9,10};
        collection.addAll(Arrays.asList(moreInts));
        System.out.println(collection);   //Output:[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
        Collections.addAll(collection, 11,12,13,14,15);
        System.out.println(collection);   //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
        Collections.addAll(collection, moreInts);
        System.out.println(collection);   //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 6, 7, 8, 9, 10]
        List<Integer> list = Arrays.asList(16,17,18,19,20);
        System.out.println(list);   //[16, 17, 18, 19, 20]
        list.set(1,99);  //修改list下标为1的元素的值为99
        System.out.println(list);   //[16, 99, 18, 19, 20]
        //list.add(21);   //Runtime error because the underlying array cannot be resized
        				//使用Arrays.asList创建的list底层是数组,因此不能调整尺寸。
    }
}

Collection 的构造器可以接受另一个Collection,用它来将自身初始化,因此可以使用Arrays.asList()来为这个构造器产生输入。但是Collection.addAll()方法运行起来要快得多,而且构建一个不包含元素的Collection,然后调用Collection.addAll()这种方式很方便,因此它是首选方式。

Collection.addAll()成员方法一次只能接受另一个Collection对象作为参数,因此它不如Arrays.asListCollections.addAll()灵活,这两个方法使用的都是可变参数列表。

也可以直接使用Arrays.asList()的输出,将其当做List,但是在这种情况下,其底层表示的是数组,因此不能调整尺寸。如果使用add()或delete()方法在这种列表中添加或者删除元素,就会引发去改变数组的尝试,将会出现运行时的错误:Unsupported Operation(不支持的操作)。

11.4 容器的打印

Java容器类库中的两种主要类型:CollectionMap

它们的区别在于容器中每个“槽”保存的元素个数。
Collection在每个槽中只能保存一个元素。此类容器包括:List,它以特定的顺序保存一组元素;Set,元素不能重复;Queue,只允许在容器的一端插入对象,并从另一端移除对象。
Map在每个槽内保存了两个对象,即键和与之相关联的值。

ArrayList和LinkedList都是List类型,从输出上看他们都是按照被插入的顺序保存元素。
HashSet,TreeSet,LinkedHashSet都是Set类型,每个相同的项都只保存一次,不同的Set实现存储元素的方式也是不同的,HashSet是最快的获取元素方式。如果存储顺序很重要,那么可以使用TreeSet,它按照比较结果的升序保存对象;或者使用LinkedHashSet,它按照被添加的顺序保存对象。

Map中的键是唯一的,只接受存储一次。

Map.put(key, value)方法将增加一个值,并将它与某个键关联起来。Map.get(key)方法将产生与这个键相关联的值。

Map:HashMap,TreeMap, LinkedHashMap。与HashSet一样,HashMap也提供了最快的查找技术,也没有按照任何明显的顺序来保存其元素。TreeMap按照比较结果的升序保存键,而LinkedHashMap则按照插入顺序保存键,同事还保存了HashMap的查询速度。

练习4:创建一个生成类,它可以在每次调用其next()方法时,产生你由你最喜欢的电影(你可以使用Snow white 或者Start Wars)的字符构成的名字(作为String对象)。在字符列表中的电影名字用完后,循环到这个字符列表的开始处。使用这个生成器来填充数组、ArrayList、LinkedList、HashSet、LinkedHashSet和TreeSet,然后打印每一个容器。

class MovieNameGenerator   {
    String[] characters = {
            "Grumpy", "Happy", "Sleepy", "Dopey", "Doc", "Sneezy", "Bashful", "Snow White", "Witch Queen", "Prince"
    };
    int next;
    public String next(){
        String r = characters[next];
        next = (next + 1) % characters.length;
        return r;
    }
}

public class E04_MovieNameGenerator {
    private static final MovieNameGenerator mng = new MovieNameGenerator();
    static String[] fill(String[] array){
        for (int i = 0; i < array.length; i++){
            array[i] = mng.next();
        }
        return array;
    }
    static Collection<String> fill(Collection<String> collection){
        for (int i = 0; i < 5; i++){
            collection.add(mng.next());
        }
        return collection;
    }

    public static void main(String[] args) {
        System.out.println(Arrays.toString(fill(new String[5])));   //[Grumpy, Happy, Sleepy, Dopey, Doc]
        System.out.println(fill(new ArrayList<>()));    //[Sneezy, Bashful, Snow White, Witch Queen, Prince]
        System.out.println(fill(new LinkedList<>()));   //[Grumpy, Happy, Sleepy, Dopey, Doc]
        System.out.println(fill(new HashSet<>()));  //[Prince, Sneezy, Snow White, Bashful, Witch Queen]
        System.out.println(fill(new LinkedHashSet<>()));    //[Grumpy, Happy, Sleepy, Dopey, Doc]
        System.out.println(fill(new TreeSet<>()));  //[Bashful, Prince, Sneezy, Snow White, Witch Queen]
    }
}

11.5 List

两种类型的List:
基本的ArrayList,它常用于随机访问元素,但是在List的中间插入和移除元素时比较慢。
LinkedList:它通过代价比较低的在List中间进行插入和删除操作,提供了优化的顺序访问,在随机访问方面相对比较慢,但是它的特性集较ArrayList更大。

下面实例通过导入typeinfo.pets,可以看到list的常用方法:
typeinfo.pets的jar包:链接: https://pan.baidu.com/s/17ba6RNplxR4sEEWVug3A8g 提取码: ptsv

import typeinfo.pets.*;

import java.util.*;

public class ListFeatures {
    public static void main(String[] args) {
        Random rand = new Random(47);
        List<Pet> pets = Pets.arrayList(7);
        System.out.println( "1:" + pets);   //1:[Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
        Hamster h = new Hamster();
        pets.add(h);
        System.out.println("2:" + pets);    //2:[Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug, Hamster]
        System.out.println(pets.contains(h)); //true
        pets.remove(h);
        System.out.println("3:" + pets);    //3:[Rat, Manx, Cymric, Mutt, Pug, Cymric, Pug]
        Pet p = pets.get(2);
        System.out.println("4:" + p +" " + pets.indexOf(p));    //4:Cymric 2
        Pet cymric = new Cymric();
        System.out.println("5:" + pets.indexOf(cymric));    //5:-1   不包含
        System.out.println("6:" + pets.remove(cymric));     //6:false
        System.out.println("7:" + pets.remove(p));  //7:true
        System.out.println("8:" + pets);    //8:[Rat, Manx, Mutt, Pug, Cymric, Pug]
        pets.add(3, new Mouse());
        System.out.println("9:" + pets);    //9:[Rat, Manx, Mutt, Mouse, Pug, Cymric, Pug]
        List<Pet> sub = pets.subList(1,4);
        System.out.println("subList:" + sub);   //subList:[Manx, Mutt, Mouse]
        System.out.println("10:" + pets.contains(sub)); //10:false
        System.out.println("10:" + pets.containsAll(sub));  //10:true
        Collections.sort(sub);
        System.out.println("sorted subList: " + sub);   //sorted subList: [Manx, Mouse, Mutt]
        System.out.println("11: " + pets.containsAll(sub)); //11: true  排序之后  仍然包含
        Collections.shuffle(sub, rand);
        System.out.println("shuffled subList:" + sub);  //shuffled subList:[Mouse, Manx, Mutt]
        System.out.println("12:" + pets.containsAll(sub));  //12:true
        List<Pet> copy = new ArrayList<Pet>(pets);
        System.out.println("copy:" + copy);
        System.out.println("pets:" + pets);     //pets:[Rat, Mouse, Manx, Mutt, Pug, Cymric, Pug]
        sub = Arrays.asList(pets.get(1), pets.get(4));
        System.out.println("sub:" + sub);   //sub:[Mouse, Pug]
        copy.retainAll(sub);    //保留,取交集
        System.out.println("13:" + copy);   //13:[Mouse, Pug]
        copy = new ArrayList<>(pets);   //Get a fresh copy
        copy.remove(2);
        System.out.println("14:" + copy);   //14:[Rat, Mouse, Mutt, Pug, Cymric, Pug]
        copy.removeAll(sub);
        System.out.println("15:" + copy);   //15:[Rat, Mutt, Cymric, Pug]
        copy.set(1,new Mouse());    //replace an element
        System.out.println("16:" + copy);   //16:[Rat, Mouse, Cymric, Pug]
        copy.addAll(2,sub);
        System.out.println("17:" + copy);   //17:[Rat, Mouse, Mouse, Pug, Cymric, Pug]
        System.out.println("18:" + pets.isEmpty()); //18:false
        pets.clear();
        System.out.println("19:" + pets);   //19:[]
        System.out.println("20:" + pets.isEmpty()); //20:true
        pets.addAll(Pets.arrayList(4));
        System.out.println("21:" + pets);   //[Manx, Cymric, Rat, EgyptianMau]
        Object[] o = pets.toArray();
        System.out.println("22:" + o[3]);   //22:EgyptianMau
        Pet[] pa = pets.toArray(new Pet[0]);
        System.out.println("23:" + pa[3].id()); //23:14
    }
}

在第五和第六的打印中可能会有些不解,这是因为List的行为根据equals()的行为而有所变化。在确定一个元素是否属于某个List,发现某个元素的索引,以及从某个List中移除一个元素时,都会用到equals()方法(它是根类Object的一部分)。
在输出行7和8中,可以看到对精确匹配List中某个对象的对象进行移除是成功的,因为这两个引用对象指向了同一个对象。

retainAll()方法是一种有效的交集额操作,如13行输出

通过使用toArray()方法,可以将任意的collection转换为一个数组。这是一个重载方法,将其无参数版本转换为Object数组。

练习7:创建一个类,然后创建一个用你的类的对象进行初始化过的数组。通过使用subList()方法,创建一个你的List的子集,然后在你的List中移除这个子集。

class IDClass{
    private static int counter;
    private int count = counter++;
    public String toString(){
        return "IDClass " + count;
    }

}

public class E07_TestList {
    public static void main(String[] args) {
        IDClass[] ids = new IDClass[10];
        for (int i = 0; i < ids.length; i++){
            ids[i] = new IDClass();
        }
        List<IDClass> lst = new ArrayList<>(Arrays.asList(ids));
        System.out.println( "lst:" + lst);      //lst:[IDClass 0, IDClass 1, IDClass 2, IDClass 3, IDClass 4, IDClass 5, IDClass 6, IDClass 7, IDClass 8, IDClass 9]
        List<IDClass> subSet = lst.subList(lst.size()/4, lst.size()/2);
        System.out.println("subSet = " + subSet);       //subSet = [IDClass 2, IDClass 3, IDClass 4]
        System.out.println("index = " + lst.size()/4);      //index = 2
        //lst.removeAll(subSet);  //这两句功能是相同的,都可以清除lst中的subSet的内容
        //subSet.clear();
        subSet.set(0, new IDClass());   // subList中的修改  是可以同步到 lst中的,因为截取并没有创建新的对象,只是创建一个引用对象
        System.out.println("subSet = " + subSet);
        System.out.println("lst:" + lst);
    }
}

11.6 迭代器

迭代器是一个对象,它的工作是遍历并选择序列中的对象。

Java中的Iterator只能单向移动,这个Iterator只能用来:

  1. 使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。
  2. 使用next()获得序列中的下一个元素。
  3. 使用hasNext()检查序列中是否还有元素。
  4. 使用remove()将迭代器最新返回的元素删除。

示例:

import typeinfo.pets.Pet;
import typeinfo.pets.Pets;

import java.util.Iterator;
import java.util.List;

public class SimpleIterator {
    public static void main(String[] args) {
        List<Pet> pets = Pets.arrayList(12);
        Iterator<Pet> iterator = pets.iterator();
        while (iterator.hasNext()){
            Pet p = iterator.next();
            System.out.print(p.id() + ":" + p + " ");
        }
        //Output:0:Rat 1:Manx 2:Cymric 3:Mutt 4:Pug 5:Cymric 6:Pug 7:Manx 8:Cymric 9:Rat 10:EgyptianMau 11:Hamster
        System.out.println();
        for (Pet p : pets){
            System.out.print(p.id() + ":" + p + " ");
        }
        System.out.println();
        // an iterator can also remove elements
        System.out.println(iterator);
        iterator = pets.iterator();
        for (int i = 0; i < 6; i++){
            iterator.next();
            iterator.remove();
        }
        System.out.println(pets);
    }
}

在最后删除之前又使用了一次iterator = pets.iterator();将迭代器初始化,第一次看到这个感觉好像这句多余了,前面已经有了初始化了,就将这句先注释掉运行一下,发现竟然没有输出pets!!!这就跟神奇了,然后想着是不是遍历一遍之后,Iterator就自动清零了或者变为null了呢?尝试直接打印iterator看看,结果输出iterator:java.util.ArrayList$Itr@78308db1,这就证明迭代器遍历之后仍然存在,这时候突然想到c语言中的指针,遍历之后,指针将移动到容器的最后一个元素后面的下标了,这时候再使用迭代器遍历,就没有东西了,为了验证这个,尝试打印iterator.hasNext()果然为false,验证了我的猜测是正确的。

如果只是编列List,并不打算修改List对象本身,使用foreach语法会更加简洁。

Iterator还可以移除由next()产生的最后一个元素,这意味着在调用remove()之前必须先调用next()。

11.7 LinkedList

练习14:创建一个空的LinkedList<Integer>,通过使用ListIterator,将若干个Iterator插入这个List中,插入时,总是将他们插入到List的中间。(这个是真的没有看懂,那个判断偶数是怎能玩的)

public class E14_MiddleInsertion {
    public static void main(String[] args) {
        LinkedList<Integer> list = new LinkedList<>();
        ListIterator<Integer> it = list.listIterator();
        for (int i = 1; i <= 10; i++){
            it.add(i);
            if (i % 2 == 0){
                it.previous();
            }
        }
        System.out.println(list);
    }
}

11.8 栈 Stack

“栈”通常指“先进后出(LIFO)”容器。有时栈也被称为叠加栈,因为最后压入栈的元素,第一个弹出栈。

Stack是使用LinkedList实现的。peek()方法返回栈顶的元素,但是并不是将其从栈顶移除,而pop()将移除并返回栈顶元素。

练习15:请使用net.mindview.util.Stack对下面的表达式求值,其中“+”表示将后面的字母压进栈,而“-”表示弹出栈顶字母并打印它:“+U+n+c---+e+r+t---+a-+i-+n+t+y---+ -+r+u--+l+e+s---

import java.util.Stack;

public class E15_Evaluator {
    private static final Stack<Character> STACK = new Stack<>();
    private static void evaluate(String expr){
        char[] data = expr.toCharArray();
        for (int i = 0; i < data.length;){
            switch (data[i++]){
                case '+' :
                    STACK.push(data[i++]);
                    break;
                case '-' :
                    System.out.print(STACK.pop());
            }
        }
    }

    public static void main(String[] args) {
        evaluate("+U+n+c---+e+r+t---+a-+i-+n+t+y---+ -+r+u--+l+e+s---");
    }
}
/* Output: 
cnUtreaiytn ursel
*///:~ 

11.9 Set

Set不保存重复的元素。如果试图将相同对象的多个实例添加到Set中,那么它就会阻止这种重复现象,这种阻止不是报错,而是忽略添加此重复的对象。
可以看一下Set的add方法的注释:add方法的返回值是boolean类型的,如果插入成功返回true,否则返回false。

    /**
     * Adds the specified element to this set if it is not already present
     * (optional operation).  More formally, adds the specified element
     * <tt>e</tt> to this set if the set contains no element <tt>e2</tt>
     * such that
     * <tt>(e==null&nbsp;?&nbsp;e2==null&nbsp;:&nbsp;e.equals(e2))</tt>.
     * If this set already contains the element, the call leaves the set
     * unchanged and returns <tt>false</tt>.  In combination with the
     * restriction on constructors, this ensures that sets never contain
     * duplicate elements.
     *
     * <p>The stipulation above does not imply that sets must accept all
     * elements; sets may refuse to add any particular element, including
     * <tt>null</tt>, and throw an exception, as described in the
     * specification for {@link Collection#add Collection.add}.
     * Individual set implementations should clearly document any
     * restrictions on the elements that they may contain.
     *
     * @param e element to be added to this set
     * @return <tt>true</tt> if this set did not already contain the specified
     *         element
     * @throws UnsupportedOperationException if the <tt>add</tt> operation
     *         is not supported by this set
     * @throws ClassCastException if the class of the specified element
     *         prevents it from being added to this set
     * @throws NullPointerException if the specified element is null and this
     *         set does not permit null elements
     * @throws IllegalArgumentException if some property of the specified element
     *         prevents it from being added to this set
     */
    boolean add(E e);

Set中最常被使用的是测试归属性,你可以很容易的询问某个对象是否在某个Set中。正因如此,查找成了Set中最重要的操作,通常在使用Set时,会选择HashSet,因为它专门对快速查找进行了优化。

下面是一个存放Integer对象的HashSet的示例:

public class SetOfInteger {
    public static void main(String[] args) {
        Random random = new Random(47);
        Set<Integer> intSet = new HashSet<Integer>();
        for (int i = 0; i < 10000; i++){
            intSet.add(random.nextInt(30));
        }
        boolean add = intSet.add(10);
        System.out.println(add);
        System.out.println(intSet);
    }
}

但是让我不解的是,按理说使用的是HashSet,应该是乱序的,书上的intSet输出就是乱序的,而我用IDEA运行输出是经过排序的,输出是0-29从小到大排序的,我又尝试使用myeclipse运行,结果又不一样了,15之前的数是排序,15后面的数,顺序不对?????

myeclipse:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 17, 16, 19, 18, 21, 20, 23, 22, 25, 24, 27, 26, 29, 28]
	 IDEA:[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]

可以看到这里只存了0-29之间的数,每个数只有一个实例出现在结果中。

而使用TreeSet时,IDEA和Myeclipse的输出都是从小到大排序的。
使用Set比较多的就是使用contains() 方法用来判断其归属性。如果Set中存在某个元素,则返回true。

11.10 Map

Map可以返回它的键的Set,它的值的Collection,或者它的键值对的Set。

keySet()方法产生了Map中的所有键组成的Set,它在foreach语句中被用来迭代遍历该Map。

对一个HashMap中的键值对进行排序:先用keySet()方法抽取所有的键,排序之后,再将结果放入LinkedHashMap里面。

public class E18_MapOrder {
    public static void main(String[] args) {
    	// 填充Map
        Map<String, String> m1 = new HashMap<String, String>(Countries.capitals(25));
        System.out.println(m1);
        // 获取Map的键
        String[] keys = m1.keySet().toArray(new String[0]);
        Arrays.sort(keys);
        Map<String, String> m2 = new LinkedHashMap<String, String>();
        for (String key : keys) m2.put(key, m1.get(key));
        System.out.println(m2);
    }
}

11.11 Queue 队列

队列是一个典型的先进先出的容器,即从容器的一端放入事物,从另一端取出,并且事物放入容器的顺序和取出的顺序是相同的。

LinkedList提供了方法以支持队列的行为,并且它实现了Queue接口,因此LinkedList可以用作Queue的一种实现。通过将LinkedList向上转型为Queue。

public class QueueDemo {

    public static  void printQ(Queue queue){
        while (queue.peek() != null){
            System.out.print(queue.remove() + " ");
        }
        System.out.println();
    }

    public static void main(String[] args) {
        Queue<Integer> queue = new LinkedList<>();
        Random random = new Random(47);
        for (int i = 0; i < 10; i++){
            queue.offer(random.nextInt(i + 10));
        }
        printQ(queue);
        Queue<Character> qc = new LinkedList<>();
        for (char c : "Brontosaurus".toCharArray()){
            qc.offer(c);
        }
        printQ(qc);
    }
}
/* Output::
	8 1 1 1 5 14 3 1 0 1 
	B r o n t o s a u r u s 
*/

offer()方法是与Queue相关的方法之一,它在允许的情况下,将一个元素插入到队尾,或者返回false。
peek()和element()都将在不移除的情况下返回队头,但是peek()方法在队列为空时返回null,而element()会抛出NoSuchElementException异常。
poll()和remove()方法将移除并返回队头,但是poll()在队列为空时返回null,而remove()会抛出NoSuchElementException异常。

11.12 Collection和Iterator

猜你喜欢

转载自blog.csdn.net/linmengmeng_1314/article/details/85472181