美文网首页
Java编程思想(九)

Java编程思想(九)

作者: MikeShine | 来源:发表于2019-05-19 10:18 被阅读0次

    第11章 持有对象

    若果一个程序只包含固定数量的且生命周期都是已知的对象,那么这是一个非常简单的程序。

    书上第一句话就是这个,什么意思呢?就是说很多时候我们事先都不知道创建对象的数量和生命周期,不是简单的程序,这个时候就要用到我们第一章说到的容器的概念。
    从这里,引出了本章所讲授的内容,即 java 中的容器。

    Java 中基本的容器有:List/Set/Queue/Map

    11.1 泛型和类型安全的容器

    这一个小节想告诉我们,在创建容器的时候,最好使用“泛型”来创建一个安全的容器。
    书上给出了两个例子作为对比。

    package holding;
    
    import java.util.ArrayList;
    
    class Apple{
        private static long counter;
        private final long id = counter++;
        public long id(){return id;}
    }
    class Orange{}
    
    public class ApplesAndOranges {
        @SuppressWarnings("unchecked")
        public static void main(String args[]){
            ArrayList apples = new ArrayList();
            for(int i=0;i<3;i++)
                apples.add(new Apple());
            // 添加一个 Orange 对象也是不被拒绝的
            apples.add(new Orange());
            for(int i=0;i<apples.size();i++){
                ((Apple)apples.get(i)).id();
                //  运行的时候才会检测到容器中有一个不同类型的元素
            }
        }
    }
    

    在上面这个例子中,我们在声明容器 apple 对象的时候,并没有给出泛型来指定其中存放的元素类型,于是,在添加一个 Orange 对象时候,编译也是正确的,直到访问元素时候系统才会发现错误。
    与之相对应的是,在一开始声明 容器的时候就使用泛型来指定容器中的对象类型:

    ArrayList<Apple> apples = new ArrayList<Apple>();
    

    这样在添加元素时候,编译器就会检查出相应的错误,这就是所谓的类型安全的容器的声明方法。
    这里可以用 foreach 语法来访问 List 中的元素,同样List中支持 upcast。看一下下面这个例子。

    package holding;
    
    import java.util.ArrayList;
    
    class GrannySmith extends Apple{}
    class Gala extends Apple{}
    class Fuji extends Apple{}
    class Braebrun extends  Apple{}
    
    public class GenericsAndUpcast {
        public static void main(String args[]){
            ArrayList<Apple> apples = new ArrayList<Apple>();
            apples.add(new GrannySmith());
            apples.add(new Gala());
            apples.add(new Fuji());
            apples.add(new Braebrun());
            for(Apple c:apples){  // upcast
                System.out.println(c); // 自动调用 toString()方法
            }
        }
    }
    

    11.2 基本概念

    Java 容器类库的用途是“保存对象”,将其划分成为两个不同的概念:
    1)Collection。一个独立元素的序列,这些元素都符合一定的规则。比如List,是要按照一定的顺序插入;又比如Set,不能有重复的元素;再比如Queue,按照排队顺序来确定对象产生的顺序。
    2) Map。“键值对”对象,是一种映射表,也叫做“关联数组”。

    // 给一个例子
    Collection c = new ArrayList<Integer>();   // upcast
    

    这里所谓的基本概念就是,总的来说,容器分成两个不同的概念,键值对的 Map是一个,剩下的是另外一个。

    11.3 添加一组元素

    这里书上给出了 Arrays 类 和 Collection类里面添加元素的一些方法,不止是可以简单的 add()。
    这里主要是 Arryas.asList() 和 Collections.addAll() 两个静态方法。

    package holding;
    
    import java.util.*;
    
    public class AddingGroups {
        public static void main(String args[]){
            // Arryas.asList(1,2) 方法,接收逗号分隔的元素列表,
                // 将其转为一个 List
            Collection<Integer> collection =
                new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));
            Integer[] moreInts = {6,7,8,9,10};
            // addAll() 方法
            collection.addAll(Arrays.asList(moreInts));
            // 注意 .addAll()是C类中的静态方法。
                // 其接受一个 Collection对象以及一个列表
            Collections.addAll(collection,1,2,3);   // 即把列表添加到哪个对象。
            // 也是静态方法
            List<Integer> list = Arrays.asList(1,3,4,6);
            //! list.add(1) 因为用上面方法得来底层表示的是数组,
                // 所以不能改变长度了。
        }
    }
    

    11.4 容器的打印

    之前我们说过,对数组的打印我们用 Arrays.toString() 这个方法。但是这里的容器打印不需要任何帮助,直接输出容器对象就可以。
    下面的几个小节就来看一下几个常用的容器类型。

    11.5 List

    List接口在Collection的基础上添加了大量方法,使得List可以在中间插入和移除元素。
    两种List:

    • ArrayList:基本的List,在随机访问元素时较快,但是在中间插入和移除较慢
    • LinkedList:和上面相反。

    书上给出了一个很长的例子,这里看一下其中用到的方法。

    • contains() 方法来确定对象是否在列表中,
    • remove() 方法
    • indexOf() 方法 返回索引
    • subList() 方法,从整个List中拿出一个片段(子List)
    • toArray() 方法,将List转换成一个数组

    11.6 迭代器

    通常情况下,对容器的访问方式的代码,我们都需要添加具体的容器中元素的类型,如果容器换了,类型变了,我们的之前写的访问的代码也就需要重新来写。
    而迭代器给我们提供了一种不需要定义具体类型的访问方式。
    Java的Iterator只能单向移动,一般的用法是这样的:
    1)使用方法 Iterator() 要求容器返回一个 Iterator。Iterator将准备好返回序列的第一个元素。
    2)使用 next() 获得序列的下一个元素
    3)使用 hasNext() 来检查序列中是否还有元素
    4)使用 remove() 将迭代器新返回的元素删除

    比如我们这里需要,写一个遍历访问 List的方法

     public static void diaply(Iterator<Pet> it){
            while(it.hasNext()){
                Pet p = it.next();
                System.out.println(p.id()+":"+p+" ");
            }
        }
    

    11.7 LinkedList 链表

    书上给了一个例子说明链表中的特有的方法:

    • getFirst(),element(),peek() 三者都是获得第一个元素,当链表为空时,peek()方法返回 null,其余二者报错
    • remove(),removeFirst(),poll() 三者都是移除 表头的元素并返回,链表为空,poll() 方法返回 null,其余二者报错
    • addFirst(),add(),offer(),addLast() 四者都是添加元素到末尾。
    • removeLast() 移除并返回列表的最后一个元素

    具体还有很多方法,这里只是介绍了最常用的一些方法。可以查阅java官方的接口文档。

    11.8 Stack

    stack 就是我们说的“后进先出”的容器。而由于链表的特性,其可以实现栈的所有功能,所以通常可以把一个链表当做 stack 使用。
    所以书上给了两个代码例子,第一个是通过 LinkedList来实现 Stack 的所有功能,另外一个就是直接用 Stack类。

    11.9 Set

    在上面的基础概念中我们说了,容器就分为 Collection和 Map。而这里的 Set 作为 Collection中的概念,其实际上就是 Collection,只是行为不同。
    Set 的继承接口有 HashSet 和 TreeSet 。前者是无序的,而后者是可以对结果进行排序的。

    11.10 Map

    Map 数组可和其他的 Collection数组一样是可以扩展到多维的。通过把元素设置为 Map对象这样来做,相当于多层嵌套实现多维。(跟我们python中的 json 很像)

    11.11 Queue

    之前说了 Stack 是后进先出的代表,而这里的 Queue 则是先进先出的容器。就是说从屁股放进去,从脑袋取出来。LinkedList 提供了非常多的方法,所以除了我们前面说的其可以实现 Stack,这里其实也是可以实现 Queue的数据结构的。

    11.13 Foreach与迭代器

    这个语句,很好用,之前我们在访问数组时候,如果不需要index,foreach 语句就非常方便。

    for(Integer i:nums[]){
        i++;
    }
    
    

    这里同样的,foreach语句可以用来访问 Collection。再结合我们之前说的迭代器。

     public static void diaply(Iterator<Pet> pets){
          for(Pet p: pets){
                System.out.println(p.id()+":"+p+" ");
            }
        }
    

    总结一下,这一章就是,讲了一些接口,后面如果具体用到的话可以去查阅一下接口文档。所以这一章大概看一哈就行了。

    相关文章

      网友评论

          本文标题:Java编程思想(九)

          本文链接:https://www.haomeiwen.com/subject/ynufzqtx.html