面向对象的编程-Application 16

Previously on OOP:

To implement Iterator, firstly, it is possible to use hasNext() and next() pair of methods defined in another class. Secondly, iterator() function in another class can also work. Thirdly, substitute with for or for each statement.

Iterable, Iterator and Comparable是三个我们曾经使用过的interfaces。Interface也可以由开发者自己定义。此外,还有functional Interface,这是一种特殊的Interface,因为里面只含有一个(abstract的)函数。

因为是functional Interface的例子,所以首先要有一个自定义的interface。为了增加难度系数,本黄鸭打算采用nested class的形式,把Interface定义在Functional class的大括号中。

新Interface的名称是Operation,里面只有一个method,名称是perform()。这个函数只有函数头没有函数体,是因为Interface中的函数全部默认为abstract的,除非特殊说明。

接下来,在Functional class中还新定义了一个函数,叫做forEach()。接收两个参数,分别是一个Object类型的数组,另外一个是Operation类型的变量。在函数体中运用for each循环,让临时变量Object o依次指向数组中的每一个元素,并且把数组中的元素传递给Operation类的perform()函数。

forEach()函数的机制比较复杂,所以请各位宝宝们多看几遍。简单来说就是遍历数组,把数组的元素依次作为参数,执行了好多遍的是Operation类的perform()函数。

在main()函数的开始,我们声明一个数组,叫做names。里面存放的元素是String类型的object references,值分别是和“鸭”有关的一些内容。

本黄鸭的目标是遍历names数组,并且打印出所有的元素。第一种方式,也就是考试中最应该采纳的方式,就是用for or for each statement循环遍历,依次打出。

当然,现在是为了举一个functional Interface的例子,所以我们试着调用一下刚才编好的forEach()函数。这个函数需要的第一个参数就是names数组。第二个参数是Operation类型的。

Operation是一个Interface,不能直接创建它的实例。那么就只剩下一条路可以走,就是再声明一个Operation Interface的子类,创建子类的实例。其中,“Operation Interface的子类”可以是nested class,也可以普通的class。用Nested class中的anonymous class最好,因为使得编码更加compact。以上的分析过程在Iterable中已经有过一次。

现在,本黄鸭就用anonymous class来创建一个Operation Interface的子类的实例。在第二个参数的位置上,框架是:

花括号中必须重载所有Operation Interface中的abstract methods,也就是perform()函数。重载的时候函数头已定,不需要纠结;函数体是打印这个变量。

在理论部分我们学过:Lambda expression可以表达functional interface里面的函数。表达什么?怎么表达?请继续阅读本文。

forEach()函数的第二个参数是Operation类型的,所以整个Lambda expression的结果肯定是Operation类型的,否则编译就不过。

在Lambda expression的左边,是临时变量o。没有写类型的原因是编译器自己会判断为Operation类型;如果想要清晰地、明确地写出o的类型,也是可以的,只要在前面加上“(Operation)”即可。

在Lambda expression的右边,是写表达式的位置,本段代码的表达式是打印出变量o。

Lambda expression的中间用“->”符号连接。在C语言中,这个符号表示调用,这里即可以这么理解,也不可以。先说为什么“不可以”:

(1)箭头符号是Lambda expression的一个组成部分。

(2)左边不是char*这种指针,是一个object reference。

(3)右边也不是函数,而是一个表达式。

(4)在Java中,使用object reference调用一个函数,必须用dotted notation连接。

再说为什么“可以”:需要被重载的函数是perform(),它的函数体又调用了println()函数,所以完全可以当做就是println()函数。

不管怎么理解,最重要的是要记住Lambda expression的结构:

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

微信公众号二维码:

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

扫码关注云+社区

领取腾讯云代金券