资讯专栏INFORMATION COLUMN

《Java编程思想》笔记11.持有对象

newtrek / 997人阅读

摘要:迭代器通常被成为轻量级对象创建它的代价很小。与迭代器可以用于数组和所有对象,之所以能够工作,是因为继承了接口。

点击进入我的博客

我觉得本章名字改成容器似乎更好理解,持有对象让人感到一头雾水
我们需要在任意时刻和任意位置创建任意数量的对象,所以依靠创建命名的引用来持有对象已经满足不了需求。
Java可以用数组和其他容器类来(List、Set、Queue、Map)来解决这个问题,不同的容器类有各自的特性,满足不同的需求。

11.1 范型和类型安全的容器

Java SE5之前是没有范型的,一个容器内(以List为例)可以放置任意的对象。

public class Test  {
    // 用@SuppressWarnings抑制编译器对“不受检查的异常”的警告
    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        // (1)
        List strList = new ArrayList() {
            {
                add("spidersama");
                add(520);
            }
        };
        // (2)
        for (Object obj : strList) {
            System.out.println(((String) obj).length());
        }
    }
}
没有范型的问题:

如上所示,(1)处的代码在编译和运行的时候都没有任何问题;但是当你在(2)处需要把Object类型强制转型成你需要的对象类型的时候,这个时候就会出现问题,因为Integer是无法转型成String类型的。

范型的好处

所以更安全的做法是,我们在创建一个容器的时候就明确它能存放的类型是什么List strList = new ArrayList<>();

编译器将阻止我们放置其他类型的对象;

而且你在从容器中取出对象的时候,也不必在强制转型,因为List知道你需要的对象类型是什么,它将会帮你自动转型。

我们可以将声明类型的子类放入该容器(即子类的向上转型)。

11.2 基本概念

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

Collection:一个独立元素的序列。所有Collection都可以用foreach遍历。

Map:一组成对的“键值对”对象,允许你使用键来查找值。

11.3 添加一组元素

Arrays.asList();

Collections.addAll();

collection.addAll();

Collection的构造器可以接受一个Collection来初始化

        Collection collection = new ArrayList<>(Arrays.asList(1, 2, 3));
        collection.addAll(Arrays.asList(new Integer[]{1, 2, 3}));

        Arrays.asList(new int[]{1, 2, 3});
        Arrays.asList(1, 2, 3);

        Collections.addAll(collection, new Integer[]{1, 2, 3});
        Collections.addAll(collection, 1, 2, 3);

注意:Arrays.asList()返回的ArrayList不可以添加元素,此ArrayList和java.util.ArrayList不是同一个类。

11.4 容器的打印

如果你要打印一个数组,需要用Arrays.toString()方法,直接打印数组显示的是[I@61bbe9ba这种之前介绍过的格式。

容器由于重写了toString()方法,所以可以直接打印出可读性强的结果。

由于不同CollectionMap的子类元素放置的规则和顺序不同,所以向容器内添加相同的元素,打印的结果不一定相同。

HashMap提供了最快的查找技术,没有任何明显的顺序来保存其元素;TreeMap按照比较结果的升序保存键;LinkedHashMap按照插入顺序保存键,同时还保留了HashMap的查询速度。

11.5 List

List是一种可修改的序列,它允许在创建之后添加、移除元素,或者自我调整尺寸。

有两种基本的List:

基本的ArrayList,它擅长随机访问元素,但是在List的中间插入和删除元素时较慢

LinkedList,它通过代价较低的方式在List中进行插入和删除操作,提供了优化的顺序访问;但是随机访问方面相对较慢。

主要方法略
11.6 迭代器

迭代器是一个对象,他的工作是遍历并选择序列中的对象,而程序员不必知道该序列的底层结构,即将遍历序列的操作和序列底层的结构分离。
迭代器通常被成为轻量级对象:创建它的代价很小。

Java的迭代器Iterator

Java的迭代器只能向前移动

使用方法iterator()要求容器返回一个IteratorIterator准备好返回序列的第一个元素

使用next()获取序列中的下一个元素

使用hasNext()检查序列中是否还有元素

使用remove()将迭代器新近返回的元素删除

更强大的迭代器 ListIterator

它是Iterator的子类型,只能用于List的访问。

它可以双向移动

它可以返回当前位置前一个元素和后一个元素的索引(即下标)

可使用时set()方法替换访问过的最近的元素

可以使用listIterator(int index)直接创建一个指向索引处的ListIterator

11.7 LinkedList

如前所述,LinkedList也像ArrayList一样实现了基本的List接口,但是它执行插入和移除时比ArrayList要更高效,但是在随机访问操作方面要慢。
LinkedList还添加了可以使其用作栈、队列或双端队列的方法(是Queue的子类)。

LinkedList中的相同方法

正是由于LinkedList添加了栈和队列的方法,使得内部多了一些功能相同但名称不同(为了覆盖父类)的方法

getFirst() == element() ≈ peek():都是返回第一个元素,但是在空List的时候处理不一样

removeFirst() == remove() ≈ poll():都是移除并返回列表的头,但是在空List的时候处理不一样

addFirst() == addLast():都将某个元素插入队尾

11.8 Stack 栈

栈是一种先进后出(Last In First Out,LIFO)的容器(数据结构)。
LinkedList能实现栈所有的功能。

主要方法

peek():返回栈顶元素

pop():返回并移除栈顶元素

push():元素入栈

empty():栈是否为空

11.9 Set 集合

Set不保存重复的元素。
SetCollection有完全一样的接口(方法),因此没有任何额外的功能,实际上Set就是Collection只是行为不同(这就是继承和多态思想的典型应用:体现不同的行为)。

常用的几种Set

HashSet:使用的是散列函数

TreeSet:将元素存储在红-黑树数据结构中。TreeSet默认是按照字典序排序的;初始化TreeSet的时候可以设定排序的方式,如String.CASE_INSENSITIVE_ORDER就是按照字母序排列;你也可以写一个你自己的比较器Comparator

LinkedHashSet:是HashSet的扩展,但是元素顺序是按照放插入顺序保存的。

11.10 Map

键值对

11.11 Queue 队列

队列是一个典型的先进先出(First In First Out,FIFO)的容器。
队列通常被当作一种可靠的将对象从程序的一个区域传输到另一个区域的途径,尤其在并发编程中十分重要。

主要方法

offer():将元素插入队尾。

add():同offer(),但是当超出队列长度当时候抛出异常。

peek():不移除的返回队头元素;为空时返回null。

element():同peek(),为空时抛出NoSuchElementException

poll():移除并返回队头元素,为空时返回null。

remove():同poll(),为空时抛出NoSuchElementException异常。

11.11.1 PriorityQueue

优先级队列:按照优先级的顺序维护的队列。
当你在PriorityQueue上调用offer()方法来插入一个对象时,这个对象会在队列中被排序。默认的排序将使用对象在队列中自然顺序,但是你可以通过提供自己的Comparator来修改这个顺序。PriorityQueue可以确保当你调用相关方法时,获取的元素将是队列中优先级最高的元素。

11.12 Collection和Iterator

Java中,实现Collection就必须提供iterator()方法,这有的时候会带来麻烦。
直接生成Iterator是将队列与消费队列的方法链接在一起耦合度最小的方式,并且与实现Collection相比,它在序列类上所施加的约束也少得多。

11.13 Foreach与迭代器

foreach可以用于数组和所有Collection对象,之所以能够工作,是因为Collection继承了Iterable接口。

数组不是Iterable

Iterable接口包含一个能够产生Iteratoriterator()方法,并且Iterable接口被foreach用来在序列中移动。换言之,任何实现了Iterable接口的类,都可以用与foreach语法。

11.13.1 适配器方法惯用法

如果需要多个foreach遍历一个类的方法,例如该类需要支持向前和向后遍历。这是只实现Iterable是不行的,可以编写其他返回类型为Iterable的方法来满足foreach语句。这就是编写适配器

// 反向遍历部分代码
public class Test extends ArrayList {
    public Test(Collection c) {
        super(c);
    }

    public Iterable reverse() {
        return new Iterable() {
            @Override
            public Iterator iterator() {
                return new Iterator() {
                    int index = size() - 1;
                    @Override
                    public boolean hasNext() {
                        return index >= 0;
                    }

                    @Override
                    public E next() {
                        return get(index--);
                    }
                };
            }
        };
    }
}
10.14 总结

数组将数字与对象联系起来。

Collection保存单一的元素,而Map保存相关联的键值对。

List也建立数字索引与对象的关联,List能够自动扩充容量。

如果要进行大量的随机访问,就使用ArrayList;如果要经常从表中间出入或删除元素,则应该使用LinkedList。

各种Queue以及栈的行为,由LinkedList提供支持。

Map是一种将对象(而非数字)与对象相关联的设计。HashMap设计用来快速访问;而TreeMap保持“键”始终处于排序状态,所以没有HashMap快。LinkedHashMap保持元素插入的顺序,但是也通过散列提供了快速访问能力。

Set不接受重复元素。HashSet提供最快的查询速度,而TreeSet保持元素处于排序状态,LinkedHashSet以插入顺序保存元素。

不要使用已过时的Vector、Hashtable和Stack。

容器分类

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/72195.html

相关文章

  • Java编程思想》读后总结(一)

    摘要:前言编程思想这本书,陆陆续续读了年,终于基本都浏览了一遍。每个对象对外暴露接口,程序通过对象暴露的接口向对象发送消息,获取该对象的服务能力。异常处理异常处理,为编写程序阶段提供了一种预见性的防止程序崩溃的出路。 前言 《Java编程思想》这本书,陆陆续续读了1年,终于基本都浏览了一遍。通过这本书,试图理解作者的想法,才真的体会到Java思想。感谢本书的作者,不仅讲述了java的语法,更...

    hufeng 评论0 收藏0
  • Java编程思想》-- 持有对象 -- 添加一组元素

    摘要:方法接受一个对象,以及一个数组或是一个用逗号分隔的列表,并将元素添加到中。工作的很好,因为他从第一个参数中了解到了目标类型是什么。 ArrayList.asList() 接受一个数组或是用逗号分隔的元素列表,也可以用可变参数,然后将其转为一个List对象。 Collections.addAll()方法接受一个Collection对象,以及一个数组或是一个用逗号分隔的列表,并将元素添加...

    tomlingtm 评论0 收藏0
  • Java编程思想》--持有对象

    Java是面向对象的语言,对象时Java不可或缺的一个元素,基本数据类型有数组用来存储,那么对象元素有什么存储呢,这就是集合,集合是Java非常重要的一块知识,Java编程思想中的持有对象简述了集合的相关知识,下面简述集合的相关功能: showImg(/img/bVC153); 集合类我们通常称为容器 其实容器只有四种:Map、List、Set和Queue 常用的容器有ArrayList、Lin...

    dinfer 评论0 收藏0
  • Java编程思想》-- 持有对象--基本概念

    摘要:概述容器类类库的用途是保存对象,它分为两个不同的概念这是一个独立的而序列必须按照插入的顺序保存元素不能有重复元素按照排队规则来确定对象产生的顺序由键值对组成的,允许由键查找值,就像字典的目录,根据目录查找内容创建接口的不同形式对象时具体的, 概述 Java容器类类库的用途是保存对象,它分为两个不同的概念: Collection:这是一个独立的而序列 List必须按照插入的顺序保存...

    mayaohua 评论0 收藏0
  • Java编程思想》--持有对象--泛型和类型安全的容器

    摘要:层次结构如上所示,的子类都可以作为集合的元素加入到集合中,并且不会有任何影响。在实际编码中一般都建议使用类型安全的容器,这样不容易出错,出错也会在编译期间就会展现出来。 概述 说起类型安全的容器,那么什么是类型不安全的容器呢?容器用来存储数据,常见的存储数据的容器有数组和集合,数组有以下特点: 长度固定 只能存储同一种类型的数据 因为数组只能存储同一种数据类型的数据,那么它就是类型...

    nemo 评论0 收藏0

发表评论

0条评论

newtrek

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<