面向对象的编程-Application 17

Previously on OOP:

Functional Interface is by definition contains one and only one abstract method. If an argument is of type Interface, we need to create a sub-class (nested class, anonymous class) for this Interface. Furthermore, Lambda expression is the other choice.

在这篇文章中,我们举一些Collection的例子。所谓Java Genrics和Collection,可以简单地理解为数据结构,比如链表,hash,树,等等。在C语言编程中,需要掌握的是这些数据结构的增删改查是怎么实现的;而在本课程中,我们可以直接调用增删改查的库类,不用自己从零编写。

在学习Collection之前,要存放一组数据,只能放在数组里面。而现在,可以采用多种多样的数据结构。那么问题来了,我们应该怎样选择数据结构呢?

(1)看有没有唯一的主键。比如requirements的描述中说:学生的学号是每个学生唯一的标识符,那么学号就是就是主键。再比如说学生的学号可以重复,A班级有24号,B班级也有24号,那么学号就不能被视为主键。

在有主键的情况下,最好使用associative container,也就是Map,SortedMap这一些。因为这些数据结构都非常方便使用主键来查找。而没有主键的情况下,我们只好用group containers了。

(2)比较几种group containers性质(存放数据的方式)。Set的特点是不可重复性。Hash在随机位置存放数据,Tree根据自己的natural order存放,List一般是按照插入顺序存放。

如果requirements里面有大量排序操作和查找操作,最好能有序地存放数据。如果主流操作是插入,那么用Set或者是List比较好。

当然,性质的比较并不是必须的,因为requirements中可能几个操作都会有,没有一个明确的主流操作,那么用任何一种group containers的效率都会差不多。

(3)那种会用选那种。在都灵理工大学开始的《算法和数据结构》课程的口试中,一个必问的题目就是:为什么选用这种数据结构?但是本课程中没有,最重要的不是怎么选用的,而是编出来的程序能不能通过所有的tests。

但是最好不要100%都使用数组,尽量还是要用Collection,否则就彻底暴露了没有学过Java Generics这一章。

下面,本黄鸭来举一个TreeSet的例子。

main函数中的第一行代码就是数据结构的声明,里面有我们已经定好的数据结构,即TreeSet。从这里可以看出,确定数据结构的时机就在声明之时。

Collection是所有group containers的父类,所以用它作为object reference的类型非常合适。

敲完Collection和TreeSet之后,编译器会提示这两个类现在不在,问要不要import进来。Import会有两个选项:

(1)java.awt.XXXX:这是错误的库类,因为这个库类不是数据结构,而是和user interface相关的。

(2)java.util.XXXX:这是正确的库类

有的宝宝会习惯性地选第一个,将会发现函数全部不能编译,或者是运行结果全错。

尖括号,即diamond brackets,里面的类型是存放的数据的类型。在等号右边的diamond brackets中,存放数据的类型可以省略,会默认为和等号前面的一样。当然,完整地写成“TreeSet()”,也是完全可以的。

如果左右两边的两个尖括号中都没有类型会触发什么样的剧情呢?编译器会自动往里面填入“Object”。这种做法在注重类型的Java语言中是不太好的,原因如下:

(1)每次取出数据的时候,都要进行cast操作

(2)存放的元素可能会特别混乱,String, int,什么类型都有,导致遍历和比较都有困难。

另外一方面,不注重类型的语言,像Linux awk,在某些场合下也是非常有效率的。所以,尖括号中不写类型,也不是绝对的错误,要根据使用场合来决定是不是采用。只是在本课程中,是没有这样的场合的。

本段往空的TreeSet数据结构中插入了四个数据,又删掉了一个数据,最后把元素全部打印出来。

增加的第五个元素和前面加入的元素有重复,而Set的性质是“唯一性”,所以最后一个加入“Duck”的操作不会触发任何剧情。在删除“Bird”元素之后,我们打印了一下现在TreeSet里面元素的个数,如果是3个,说明删除操作成功了。

最后,打印TreeSet中所有的元素会按照什么顺序呢?Tree的性质是“nature order”,也就是按照alphabetical order从小到大。顺序应该是:Duck,Goose,Roster。

如果把数据结构从TreeSet变为HashSet,打印出来的顺序是order of hash codes,即随机顺序。

在这个例子中,需要背住的是:

这两个方法在associative containers中是不一样的名字。

接下来,本黄鸭再举一个LinkedList的例子,这是另外一种group container:

本黄鸭更喜欢把第一行的object reference的类型换成Collection。本段代码的重点在于set() and get() methods。

先来看一下set()函数,给指定位置的数据赋予新的值。If the set index was not initialized/ added / created(比如:“l.set(10, 99);”), there will be anexecutionerror, as the compilerdoesnot know which numbers can be filled into the non existing elements。而errorin execution time,只能靠Exception来处理,或者是提前判定一下有没有这个数据。

再看一下get()函数,能返回指定位置的数据的值。

所以,在这个例子中,需要背住的是:

欢迎使用本黄鸭编写的小程序~

微信公众号二维码:

  • 发表于:
  • 原文链接:https://kuaibao.qq.com/s/20181017G1K7F700?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。

扫码关注云+社区

领取腾讯云代金券