数据结构思维 第一章 接口

第一章 接口

原文:Chapter 1 Interfaces

译者:飞龙

协议:CC BY-NC-SA 4.0

自豪地采用谷歌翻译

本书展示了三个话题:

  • 数据结构:从 Java 集合框架(JCF)中的结构开始,你将学习如何使用列表和映射等数据结构,你将看到它们的工作原理。
  • 算法分析:我提供了技术,来分析代码以及预测运行速度和需要多少空间(内存)。
  • 信息检索:为了激发前两个主题,并使练习更加有趣,我们将使用数据结构和算法构建简单的 Web 搜索引擎。

以下是话题顺序的大纲:

  • 我们将从List接口开始,你将编写实现这个接口的两种不同的方式。然后我们将你的实现与 Java ArrayListLinkedList类进行比较。
  • 接下来,我将介绍树形数据结构,你将处理第一个应用程序:一个程序,从维基百科页面读取页面,解析内容,并遍历生成的树来查找链接和其他特性。我们将使用这些工具来测试“到达哲学”的猜想(你可以通过阅读 http://thinkdast.com/getphil 来了解)。
  • 我们将了解 Java 的Map接口和HashMap实现。然后,你将使用哈希表和二叉搜索树来编写实现此接口的类。
  • 最后,你将使用这些(以及其他一些我之前介绍的)类来实现一个 Web 搜索引擎,其中包括:一个查找和读取页面的爬虫程序,一个存储网页内容的索引器,以便有效地搜索,以及一个从用户那里接受查询并返回相关结果的检索器。

让我们开始吧。

1.1 为什么有两种List

当人们开始使用 Java 集合框架时,有时候会混淆ArrayListLinkedList。为什么 Java 提供两个List interface的实现呢?你应该如何选择使用哪一个?我们将在接下来的几章回答这些问题。

我将以回顾interface和实现它们的类开始,我将介绍“面向接口编程”的概念。

在最初的几个练习中,你将实现类似于ArrayListLinkedList的类,这样你就会知道他们如何工作,我们会看到,他们每个类都有优点和缺点。对于ArrayList,一些操作更快或占用更少的空间;但对于LinkedList其他操作更快或空间更少。哪一个更适合于特定的应用程序,取决于它最常执行的操作。

1.2 Java 中的接口

Java interface规定了一组方法;任何实现这个interface的类都必须提供这些方法。例如,这里是Comparable的源代码,它是定义在java.lang包中的interface

public interface Comparable<T> {
    public int compareTo(T o);
}

这个interface的定义使用类型参数T,这使得Comparable是个泛型类型。为了实现这个interface,一个类必须:

  • 规定类型T,以及,
  • 提供一个名为compareTo的方法,接受一个对象作为参数,并返回int

例如,以下是java.lang.Integer的源代码:

public final class Integer extends Number implements Comparable<Integer> {

    public int compareTo(Integer anotherInteger) {
        int thisVal = this.value;
        int anotherVal = anotherInteger.value;
        return (thisVal<anotherVal ? -1 : (thisVal==anotherVal ? 0 : 1));
    }

    // other methods omitted
}

译者注:根据Comparable<T>的文档,不必要这么复杂,直接返回this.value - that.value就足够了。

这个类扩展了Number,所以它继承了Number的方法和实例变量;它实现Comparable<Integer>,所以它提供了一个名为compareTo的方法,接受Integer并返回一个int

当一个类声明它实现一个interface,编译器会检查,它提供了所有interface定义的方法。

除此之外,这个compareTo的实现使用“三元运算符”,有时写作?:。如果你不熟悉,可以阅读 http://thinkdast.com/ternary

1.3 List接口

Java集合框架(JCF)定义了一个interface,称为 List,并提供了两个实现方式,ArrayListLinkedList

这个interface定义了List是什么意思;实现它的任何类interface必须提供一组特定的方法,包括addgetremove,以及其它大约 20 个。

ArrayListLinkedList提供这些方法,因此可以互换使用。用于List也可用于ArrayListLinkedList,或实现List的其它任何对象。

这是一个人为的示例,展示了这一点:

public class ListClientExample {
    private List list;
    
    public ListClientExample() {
        list = new LinkedList();
    }

    private List getList() {
        return list;        
    }

    public static void main(String[] args) {
        ListClientExample lce = new ListClientExample();
        List list = lce.getList();
        System.out.println(list);
    }
}

ListClientExample没有任何有用的东西,但它封装了List,并具有一个类的基本要素。也就是说,它包含一个List实例变量。我会使用这个类来表达这个要点,然后你将在第一个练习中使用它。

通过实例化(也就是创建)新的LinkedList,这个ListClientExample构造函数初始化list;读取器方法叫做getList,返回内部List对象的引用;并且main包含几行代码来测试这些方法。

这个例子的要点是,它尽可能地使用List,避免指定LinkedListArrayList,除非有必要。例如,实例变量被声明为List,并且getList返回List,但都不指定哪种类型的列表。

如果你改变主意并决定使用ArrayList,你只需要改变构造函数; 你不必进行任何其他更改。

这种风格被称为基于接口的编程,或者更随意,“面向接口编程”(见 http://thinkdast.com/interbaseprog)。这里我们谈论接口的一般思想,而不是 Java 接口。

当你使用库时,你的代码只依赖于类似“列表”的接口。它不应该依赖于一个特定的实现,像ArrayList。这样,如果将来的实现发生变化,使用它的代码仍然可以工作。

另一方面,如果接口改变,依赖于它的代码也必须改变。 这就是为什么库的开发人员避免更改接口,除非绝对有必要。

1.4 练习 1

因为这是第一个练习,我们会保持简单。你将从上一节获取代码并交换实现;也就是说,你会将LinkedList替换为ArrayList。因为面向接口编写程序,你将能够通过更改一行并添加一个import语句来交换实现。

以建立你的开发环境来开始。对于所有的练习,你需要能够编译和运行 Java 代码。我使用 JDK7 来开发示例。如果你使用的是更新的版本,则所有内容都应该仍然可以正常工作。如果你使用的是旧版本,可能会发现某些东西不兼容。

我建议使用交互式开发环境(IDE)来获取语法检查,自动完成和源代码重构。这些功能可帮助你避免错误或快速找到它们。但是,如果你正在准备技术面试,请记住,在面试期间你不会拥有这些工具,因此你也可以在没有他们的情况下练习编写代码。

如果你尚未下载本书的代码,请参阅 0.1 节中的指南。

在名为code的目录中,你应该找到这些文件和目录:

  • build.xml是一个 Ant 文件,可以更容易地编译和运行代码。
  • lib包含你需要的库(对于这个练习,只是 JUnit)。
  • src包含源代码。

如果你浏览src/com/allendowney/thinkdast,你将找到此练习的源代码:

  • ListClientExample.java包含上一节的代码。
  • ListClientExampleTest.java包含一个 JUnit 测试ListClientExample

查看ListClientExample并确保你了解它的作用。然后编译并运行它。如果你使用 Ant,你可以访问代码目录并运行ant ListClientExample

你可能会得到一个警告。

List is a raw type. References to generic type List<E> 
should be parameterized.

为了使这个例子保持简单,我没有留意在列表中指定元素的类型。如果此警告让你烦恼,你可以通过将ListLinkedList替换为List<Integer>LinkedList<Integer>来修复。

回顾ListClientExampleTest。它运行一个测试,创建一个ListClientExample,调用getList,然后检查结果是否是一个ArrayList。最初,这个测试会失败,因为结果是一个LinkedList,而不是一个ArrayList。运行这个测试并确认它失败。

注意:这个测试对于这个练习是有意义的,但它不是测试的一个很好的例子。良好的测试应该检查被测类是否满足接口的要求;他们不应该依赖于实现的细节。

ListClientExample中,将LinkedList替换为ArrayList。你可能需要添加一个import语句。编译并运行ListClientExample。然后再次运行测试。修改了这个之后,测试现在应该通过了。

为了这个此测试通过,你只需要在构造函数中更改LinkedList;你不必更改任何List出现的地方。如果你这样做会发生什么?来吧,将一个或者多个List替换为ArrayList。程序仍然可以正常工作,但现在是“过度指定”了。如果你将来改变主意,并希望再次交换接口,则必须更改代码。

ListClientExample构造函数中,如果将ArrayList替换为List,会发生什么?为什么不能实例化List

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,080评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,422评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,630评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,554评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,662评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,856评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,014评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,752评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,212评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,541评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,687评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,347评论 4 331
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,973评论 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,777评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,006评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,406评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,576评论 2 349

推荐阅读更多精彩内容

  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,598评论 18 399
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,803评论 25 707
  • 网络时代,双十一成了剁手节,当然也是光棍节,哈哈哈哈!可能是因为我忍不住购物,控制不住购物的欲望,所以双十...
    九月同学阅读 134评论 2 1
  • 我也想放个暑假。今天侄子侄女放暑假了。看着他们开心的笑容,我也回想起自己当年的暑假了。距离大学毕业已经十一年了。距...
    7ca71f76eb62阅读 182评论 0 0
  • 1.人的一生,总是面临各种各样的选择。可以选择躺在床上安逸的玩着手机,打着游戏,也可以选择去健身房挥汗如雨,热情奔...
    FlyingYe阅读 1,387评论 2 0