面向对象的编程-Application 6

Previously on OOP:

Getters and setters, as well as several other methods, have been created in Person class. In order to verify the coding correctness, we have created a PersonApp class with main function. Finally, to invoke functions one after another, just like Stream, it is necessary to return an object reference in these functions.

在本课程中,提到的第一种数据结构是数组,重要性是一百颗五角星,就算其他的数据结构全部不会,只用数组也是可以通过考试的。本黄鸭再强调一下数组的基本概念:

(1)存放在数组中的数据的类型相同,比如所有数据要么都是int类型的,要么都是Person类型的,类型不统一在Java语言中是不行的。

(2)如果存放的类型是primitive type,那么数组里面存放的就是数据本身。如果存放的类型是class,那么数组里面存放的是object reference,而不是object本身。

(3)String在C语言中可以被定义为an array of characters, terminated by“\0”,但是在Java语言中是一个class。

(4)数组和以Collection为父类的Array class是不同的,后者属于Generics章节的数据结构。

如果对于基本概念有很多问题,请移驾理论课程,并且从头开始学习。

在FirstExample project的default package中,我们新建一个带有main函数、名字叫做PersonArray的类,而且在这个类中,将要创建一个存放Person类型的数据的数组。

数组的创建分有三个步骤。第一步是声明一个数组的object reference,类型和数组中存放的元素的类型一致,此时,这是一个空指针,名字叫做persons。第二步是创建一组已知个数的object references,为了存放元素。第三步,把第二步的指针赋值给第一步的指针。这三个步骤可以用一行代码来搞定:

最后一个方括号中的数字是10,即persons数组最多能储存10个Person类型的object references。数组的下标是从开始的,所以这10个元素的下标分别是:0, 1, 2, 3, 4, 5, 6, 7, 8, 9,下标不会出现10。

现在,数组中的10个object references全是空的,我们可以让它们指向Person类的实例,如下所示:

persons[0]表示persons数组中的第一个元素,现在指向一个新建的Person类型的object,GoldenDuck。后面两个元素以此类推。

最后一行代码以persons[1]为object reference,调用Person类的print()函数,打印出来的结果是:SilverDuck-LenovoSilverDuck。

但是,把最后一行如果改成“persons[9].print();”,persons[9]是一个空指针,没有指向实例,所以程序的运行会由于NULL pointer exception而被中断。数组的元素是空指针,这是被数组允许的,因为数组中只规定最多存放的元素的个数不超,所以在调用之前,最好用if条件句判定一下指针非空。

刚才我们提到了String在Java中是一个类。现在,在FirstExample project的strings package中,我们新建一个带有main函数、名字叫做BasicStrings的类,试着把String中已经定义好的methods运用到实践中。

第一行代码是声明这个文件所在的package是strings package。接下来,一般都是import一些库类进来,以便于使用已经编写好的函数,但是String类不需要这个步骤。

创建一个String类型的object有两种做法,第一种做法非常concise,在双引号中写好想要的字符串即可。第二种做法和创建其他类的实例一样,用new关键字,并且调用constructor。本黄鸭觉得第二种方法比较好。

最后一行代码是打印出字符串的内容和字符串的长度,中间用空格连接。需要注意的是,求字符串的长度是可以通过String类中已经定义好的length()函数来完成的,相当于C语言中的strlen()函数。

然后,我们再创建一个String类的实例,object reference的名称是u,u中存放的字符串是“GOLDEN DUCK”:

然而本段代码没有采用任何一种创建String实例的办法,而是直接用“golden duck”字符串的object reference s来调用toUpperCase()函数,把“golden duck”中的所有字符都换成大写字符。由此可见,在toUpperCase()函数中,返回语句很可能写作“return this;”,即返回值是String类型的一个object reference。This is an educated guess。

如果只写了“s.toUpperCase();”,而没有把返回值赋予u会有什么样的效果呢?答案是没有任何剧情被触发,因为String class isimmutable。凡是存放的字符串要发生改变,不管是后面附加一个新的字符串,还是把所有字母都大写,还是修改得面目全非,一律要重新创建一个String类型的object reference来储存新的字符串的实例。如果还不了解String的immutable性质,请移驾理论部分,并且从头开始学习。

假设不把修改后的字符串赋值给新的object reference,而是给老的object reference,会有什么效果呢?

在“s = s.toUpperCase();”语句执行后,s中是“GOLDEN DUCK”,而backupStringReference中是“golden duck”。如果没有用backupStringReference来备份修改前的字符串,那么很有可能会变得没有任何一个object reference指向它,这块内存在Java virtual machine中变成开发者没有办法访问到的部分,所以过不了过久,garbage collector就会自动把这里清理掉。而在C语言中,计算机的内存很可能会少掉一块,出现memory leakage现象。

最后一个问题在口试的时候出现的频率非常高,两个object reference相等应该怎样理解?

“theSame”是一个布尔型的变量,它的值由backupStringReference和t两个object references是否相等来决定,只能在true或者false里面选择其一。即便是这两个object references指向的String对象里面存放的字符串都是“golden duck”,但是这两个是不同的objects。backupStringReference被赋予的是s的值,而s和t分别指向不同的实例,两个人之间没有赋值和被赋值的关系。所以,一定是else分支中的调试语句会被打印出来。

如果把第一行代码改成:

有没有可能theSame变量的值是变成true呢?本黄鸭以为答案是yes,因为两者之间存在赋值和被赋值的关系。

一般地,重要的不是两个object reference之间是否相等,而是两个实例(的内容)之间是等于,不等,大于、还是小于。比如想要把Student类的实例排序的时候,就要比较不同学生之间的大小,并且implements Comparable之类的,来定义不同学生之间的比较方法。在这个例子中,我们先暂时忘记自定义的比较方法,来看看两个字符串的实例是相等还是不等。

调用equals()函数,能判定两个实例(的内容)是否相等。这一点和C语言非常相似,比较两个字符串的内容是否相等要看strcmp()的结果是否等于,结果等于说明字符串的内容相同。而直接用“==”连接两个字符串是不行的。

本黄鸭强烈推荐背住一句话:判断两个实例是否相同,要调用equals()函数。以上就是BasicStrings类的全部内容。

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

微信公众号二维码:

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

扫码关注云+社区

领取腾讯云代金券