美文网首页
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