请用面向对象的思想,谈一谈这次面试的过程
01、
很久没有思考过什么是面向对象这个问题了,就好像很久没有吃过烤红薯一样,那股香味究竟是什么,已经很难准确地形容出来了。脑海中只浮现出这样一幅动图:
前两天,读者秋秋问我:
二哥,究竟什么是面向对象呢?还有,什么是面向过程。今天去面试的时候,面试官让我用面向对象的思想谈一谈这次面试的过程。
看到这个问题后,我思考了好一会儿,总觉得面试官的问法有点问题:为什么要用面向对象的思想谈一谈面试的“过程”?
有点矛盾,有没有?先不管这么多了,且来看看什么是面向对象吧。
一开始的时候,并没有面向对象,只有面向过程的概念。我们回到秋秋面试的话题上,把面试前(可以降低需求的复杂性)的过程简单地拆解一下。
- 秋秋投递简历
- 面试官收到秋秋的简历
- 面试官通知秋秋面试
为了实现这 3 个步骤,我们定义 3 个方法,并依次调用:
- qiuqiuDeliverResume();
- interviewerReceiveResume();
- interviewerNotifyQiuqiu();
但是,假如参加面试的不是秋秋,这 3 个方法就要重新定义了(莫抬杠),尽管步骤并没有变。面向对象从另一个角度来解决这个问题,它把对象(对事物的一种抽象描述)作为程序的基本单元。
回到秋秋面试的例子,用面向对象的思想来实现,就需要先定义 2 个类(类是构建对象的蓝图,里面包含若干的数据和操作这些数据的方法),分别是应聘者和面试官。
应聘者可以投递简历;面试官可以接收应聘者的简历和通知应聘者前来面试。然后再通过类创建两个对象,分别是秋秋和他的面试官;对象创建成功后,就可以依次调用对应的方法完成上述的 3 个步骤。
面向对象(英语:Object Oriented,缩写:OO)思想是一种试图降低代码间的依赖,应对复杂性,从而解决代码重用的软件设计思想——恰好解决了面向过程带来的问题。
面向对象有很多重要的特性,比如说封装、继承和多态。这些概念又该怎么理解呢?所谓一图胜千言,我给你来一张有趣的、形象的。
了解了面向对象的思想后,我们来通过具体的代码完成秋秋面试前的 3 个步骤。并对类和对象的相关知识点进行归纳和总结。
02、
先来细致地看一下应聘者类——Candidate.java。
package com.cmowerclass Candidate {private String name;public Candidate(String name) {this.name = name;}public void deliverResume() {System.out.println(getName() + "发简历");}public String getName() {return name;}public void setName(String name) {this.name = name;}}
Candidate 包含了类的 4 个重要概念:
- 成员变量(有时叫做域,有时叫做字段,有时叫做属性)
name
; - 成员变量访问器(有时叫做
getter/setter
)getName()
和setName()
; - 构造方法(有时叫做构造器)
Candidate()
; - 普通方法
deliverResume()
。
Candidate 类虽然简单,但却大有学问。
1)为了保证包名的绝对唯一,Sun 公司建议将域名(绝对是独一无二的)以逆序的形式作为包名——这也是为什么包名经常以 org
、com
开头的原因(是不是有一种豁然开朗的感觉)。我曾申请过一个域名,叫 cmower.com,所以我个人编写的绝大多数代码都是在 com.cmower
包下。
2)类的方法定义顺序依次是:构造方法 > 公有(public
)方法或保护(protected
)方法 > 私有(private
)方法 > getter/setter 方法。
构造方法是创建对象的必经之路,放在首位是必须的。如果只有系统默认的无参构造方法,可忽略。
公有方法是类的调用者和维护者最关心的方法,应该在比较靠前的位置展示;保护方法虽然只有子类关心,也可能是“模板设计模式”下的核心方法,所以也要靠前;私有方法只对本类可见,一般不需要特别关心,所以往后放;getter/setter
方法承载的信息价值较低,所以放在类的最后面。
3)setter 方法中,参数名称与成员变量名称保持一致,采用 this.成员名 = 参数名
的形式。
4)成员变量不要用 public
修饰,尽量用 private
修饰;如果需要被子类继承,可以用 protected
修饰。
在初学 Java 编程的时候,我经常产生一个疑惑:为什么不使用 public
修饰成员变量呢?这样做不是比 getter/setter
更方便吗?
我最先想到的答案是这样的:
解释:如果只有 private String name
而没有 getter/setter
的话,Eclipse 会提示 The value of the field Candidate.name is not used
的警告。
当然了,这样的答案过于牵强。那能不能来个靠谱点的答案呢?
能,为了体现封装的思想:将数据与行为进行分离。封装有什么好处呢?
- 隐藏类的实现细节;
- 让使用者只能通过事先定制好的方法(
getter/setter
)来访问数据,可以方便地加入控制方法,限制对成员变量的不合理操作; - 便于修改,增强代码的维护性和健壮性;
- 提高代码的安全性和规范性;
- 使程序更加具备稳定性和可拓展性。
不过,我对这些严肃的词汇和科学用语实在是提不起半点兴致。那就再换一个答案吧。
套用《Java 开发实战经典》中举过的一个例子,我们增加一个应聘者年龄的共有成员变量 age。
class Candidate {public int age;
}
然后在创建应聘者对象的时候,直接通过类成员变量赋值:new Candidate().age = -99;
这样赋值是没有任何问题的,但没有实际的意义,年龄是不可能为负数的。为了防止出现这样的错误,可以对它进行封装,也就是私有化,然后在 setter
方法中对年龄进行判断,代码如下:
class Candidate {private int age;public void setAge(int age) {if (age >= 0) {this.age = age;}}
}
这个答案你觉得满意吗?我最开始看到这个答案的时候觉得很满意。但看了《阿里巴巴 Java 开发手册》后(详情截图如下),就觉得不满意了。
第一,类成员变量使用基本类型很容易造成NullPointException
的错误;第二,在 getter/setter
增加业务逻辑的确很容易把实际的问题隐藏起来。
那,好的答案究竟是什么呢?
如果设置成员变量为 public
,那么每个调用者都可以读写它,但如果以 private
配合 getter/setter
的形式访问时,就可以达到“不准访问”、“只读访问”、“读写访问”以及“只写访问”的目的。因为不是每个成员变量都需要 getter/setter
。
5)每个类都至少会有一个构造方法。初学者可能会非常疑惑:我的那个类真的没有构造方法啊!
如果在编写一个类的时候没有编写构造方法,那么系统就会提供一个无参的构造方法,就好像是这样:
class Candidate {private String name;public Candidate() {}}
当执行 new Candidate()
的时候,成员变量 name 就会被初始化为 null
。一般情况下,我们会为类设置它必须的构造方法,然后在创建对象的时候对成员变量进行赋值。
03、
再来粗略地看一下面试官类——Interviewer.java。
class Interviewer {private Candidate candidate;public Interviewer (Candidate candidate) {this.candidate = candidate;}public void receviveResume() {System.out.println("收到" + getCandidate().getName() + "简历");}public void notifyInterview() {System.out.println("通知" + getCandidate().getName() + "面试");}public Candidate getCandidate() {return candidate;}public void setCandidate(Candidate candidate) {this.candidate = candidate;}}
Interviewer 有一个成员变量 Candidate,一个构造方法,两个共有方法,以及成员变量对应的 getter/setter
。
(这段代码存在一个严重的问题,你注意到了吗?)
04、
然后,我们让应聘者发送简历,让面试官接收简历并发送通知。
Candidate qiuqiu = new Candidate("秋秋");
// 发送简历
qiuqiu.deliverResume();Interviewer interviewer = new Interviewer(qiuqiu);
// 面试官接收到简历
interviewer.receviveResume();
// 面试官通知应聘者来面试
interviewer.notifyInterview();
在初学 Java 的很长一段时间里,我总是搞不清楚什么是“对象”,什么是“引用”,差点因此放弃我的程序生涯。后来,在网上认识了一个大佬,人称老王,是他挽救了我的程序生涯。
他解释说。
Candidate qiuqiu = new Candidate("秋秋");
可以拆分为两行代码:
Candidate qiuqiu;
qiuqiu = new Candidate("秋秋");
第一行代码 Candidate qiuqiu;
中的 qiuqiu 这时候可以称作是对象变量,它暂时还没有引用任何对象,严格意义上,它也不能称为 null
。
第二行代码 qiuqiu = new Candidate("秋秋");
可以拆分为两个部分,= 号左侧和 = 号右侧。
右侧的表达式 new Candidate("秋秋")
先执行,执行完后,会在堆上创建了一个 name 为“秋秋”的对象,类型为 Candidate,表达式 new Candidate("秋秋")
的值是新创建对象的引用。
然后再把这个引用通过 = 操作符赋值给左侧的对象变量 qiuqiu
,赋值后,qiuqiu
就不再是对象变量了,应该称为对象引用。
看完老王的解释,你会不会情不自禁地“哦,原来如此啊!”反正我当时顿悟的时候是这样的。
前面提到,Interviewer 类的设计存在一个严重的问题,是什么呢?
Candidate qiuqiu = new Candidate("秋秋");
Interviewer interviewer = new Interviewer(qiuqiu);interviewer.getCandidate().setName("夏夏");
System.out.println(qiuqiu.getName());
这段代码执行完后,你会发现秋秋变成了夏夏,应聘者的私有成员变量 name 竟然被改变了!问题的原因也很简单,qiuqiu 和 interviewer.getCandidate()
引用了同一个对象。
那怎么解决呢?当 getter
需要返回一个可变对象的引用时,应该先进行克隆(clone)。以下展示了一个非常简单的克隆方案。
class Interviewer {private Candidate candidate;public Interviewer (Candidate candidate) {this.candidate = candidate;}public Candidate getCandidate() {Candidate candidate = new Candidate(this.candidate.getName());return candidate;}}
05、
这篇文章花了 5 个多小时才写完,此刻我的感觉只有一个字——饿,我要出去吃饭了。吃饭之前,我决定先买个烤红薯吃,重温一下那种久违的香。
请用面向对象的思想,谈一谈这次面试的过程相关推荐
- 某公司要开发新游戏,请用面向对象的思想,设计游戏中的蛇怪和蜈蚣精
某公司要开发新游戏,请用面向对象的思想,设计游戏中的蛇怪和蜈蚣精 设定 蛇怪类: 属性包括:怪物名字,生命值,攻击力 方法包括:攻击,移动(曲线移动),补血(当生命值<10时,可以补加20生命值 ...
- 编写程序描述影视歌三栖艺人 需求说明:请使用面向对象的思想,设计自定义类,描述影视歌三梄艺人。 实现思路及关键代码 1)分析影视歌三栖艺人的特性 a)可以演电影 b)可以演电视剧 c)可以唱歌
编写程序描述影视歌三栖艺人 需求说明:请使用面向对象的思想,设计自定义类,描述影视歌三梄艺人. 实现思路及关键代码 1)分析影视歌三栖艺人的特性 a)可以演电影 b)可以演电视剧 c)可以唱歌 2)定 ...
- 编写程序描述影视歌三栖艺人。需求说明:请使用面向对象的思想,设计自定义类,描述影视歌三梄艺人。...
编写程序描述影视歌三栖艺人.需求说明:请使用面向对象的思想,设计自定义类,描述影视歌三梄艺人. 实现思路: 1) 分析影视歌三栖艺人的特性:可以演电影,可以演电视剧,可以唱歌 2) 定义多个接口描述特 ...
- 编写程序描述卡车信息 某公司要开发“X出租公司车辆管理系统”,请用面向对象的思想设计卡车类。
一.练习题目 编写程序描述卡车信息 二.问题描述 某公司要开发"X出租公司车辆管理系统",请用面向对象的思想设计卡车类. 设定: 属性:车牌号.车型.颜色.日租金.载重量 方法:租 ...
- 说,有一群 小孩在玩堆雪人,不时有新的小孩加入,请问如何知道现在有多少小孩在玩,请用面向对象的思想编写程序解决
先定义一个类 package leiDeDingYi_leiDeShiYong;public class Children {//成员变量String name;int age;static int ...
- 【Java设计模式 面向对象设计思想】一 再谈面向对象和封装、抽象、继承、多态四大特性
回看最初的目标:[Java设计模式 学习目标及大纲]高质量代码的标准及实现路径在这篇Blog里我们明确了什么是高质量的代码:易维护.易读.易扩展.灵活.简洁.可复用.可测试,也知道高质量代码的达成路径 ...
- 面试题: 谈一谈你对面向对象编程思想的理解?
面向对象:(编程思想) 编程思想的概念引入 面向:看.关注.瞅 对象:个体.实体.实例.结果 使用到代码中: 将整个项目拆分为一个一个的模块,然后肢解成 ...
- Java程序员谈一谈-----java程序员成长之路
转载:http://www.banzg.com/archives/679.html?ref=myread 阿里面试回来,想和Java程序员谈一谈 引言 其实本来真的没打算写这篇文章,主要是LZ得记忆力 ...
- 【转载】阿里面试回来,想和Java程序员谈一谈
原文链接:http://www.techug.com/post/alibaba-interview-java-programmer.html 其实本来真的没打算写这篇文章,主要是我得记忆力不是很好,不 ...
最新文章
- 右键 Dos在这里 删除
- FCKeditor 2.6 安装配置使用指南(asp)
- 基于SLF4J MDC机制实现日志的链路追踪
- ubuntu,kali linux和windows三系统流水账——写给自己
- 毕业了去哪里工作,一位毕业多年北漂人的经验感悟
- jQuery源码解析(5)—— Animation动画
- 全面综述:基于3D骨架的深度学习行为识别方法
- JVM垃圾回收策略与垃圾收集器
- FR公式形态定义及运用范例
- linux怎么修改数据库字段长度,Postsql 修改字段长度和类型
- python dateutil_Python3.x:日期库dateutil简介
- 项目实战:十种方法实现图像数据集降维
- TranslateAnimation详解
- html动态图片怎么设背景,[gif制作教程]如何把gif动态图片的背景变透明,仍保留有动画效果...
- Springboot定时任务、Quartz表达式
- CSDN:2020年度CSDN博客之星评选竞赛——180号【一个处女座的程序猿】,感谢您,投上的宝贵一票,感谢!感恩!
- android 日记 app推荐,有什么写日记的软件?这4个app推荐给大家!
- Python编程基础 第七章 编程练习 用户从键盘上输入一个字符串,如果该字符串的内容不是有效的数值,则输出invalid;如果是有效的数值,再判断其是否是整数,如果是整数则输出yes,否则输出no。
- 常见乱码问题分析和总结
- 2019暑期个人排位集训补题--思维题
热门文章
- 一个家庭幸不幸福,80%以上取决于女主人。有一种女人嫁给谁都幸福
- 数据库设计思想深究----Mysql(图文)
- 辅警计算机和网络知识,关于计算机辅警的考试
- matplotlib plot python rgb2gry 显示灰度图像
- 服务创新产品“在线智能问诊”——互联网平台建设...
- “数据产品”是怎样的存在?
- SuperPoint特征检测算法TrainEvaluate教程
- 数据库(十)-单表查询(1)条件查询
- 两分钟速览谷歌2023IO大会:AI军备竞争,全线出击
- 内蒙古农业大学职业技术学院——数据结构—第一课