ACCP60 S2 使用Java实现面向对象编程 第一章.docx
《ACCP60 S2 使用Java实现面向对象编程 第一章.docx》由会员分享,可在线阅读,更多相关《ACCP60 S2 使用Java实现面向对象编程 第一章.docx(36页珍藏版)》请在冰豆网上搜索。
ACCP60S2使用Java实现面向对象编程第一章
1.1用面向对象设计电子宠物系统
1.1.1为什么使用面向对象
现实世界就是“面向对象的”。
现实世界中的任何事物都可以看作是“对象”,比如人、建筑、交通工具、学习用品等。
而事物都有自己的属性和行为。
比如人,它具有各种属性:
姓名、性别、身高、体重、籍贯等,还可以做很多事情:
吃饭、睡觉、劳动、锻炼等。
各个事物之间还会发生各种联系,人用木材可以做成一套家具,人用笔可以写出文章等。
面向对象就是采用“现实模拟”的方法设计和开发程序。
计算机软件开发规模越来越大,解决的问题也越来越复杂,导致软件开发时间、软件开发成本、软件维护费用甚至软件开发质量等日益难以控制。
而面向对象技术利用“面向对象的思想”去描述“面向对象的世界”,实现了虚拟世界和现实世界的一致性,符合人们的思维习惯,使得客户和软件设计开发人员之间、软件设计开发人员内部交流更加顺畅,同时还带来了代码重用性高、可靠性高等优点,大大提高了软件尤其是大型软件的设计和开发效率。
问答
问题:
面向过程和面向对象有什么区别?
解答:
我们要举办一次北大青鸟的联欢晚会。
如果采用面向过程的话,就是全体人员合唱青鸟之歌→主持人宣布晚会开始→领导讲话→主持人过场→演员一表演→主持人过场→演员二表演……→最后一位演员表演→主持人宣布晚会结束,即从头至尾、自上而下的实现功能。
而如果采用面向对象实现的话,首先分析晚会需要哪些类:
领导、主持人和演员。
然后分析各种类的行为:
主持人有宣布晚会开始、过场、宣布晚会结束,当然也有唱青鸟之歌。
领导有讲话、唱青鸟之歌。
演员主要就是表演节目,也有唱青鸟之歌。
然后就利用设计好的类创建对应对象,调用相应的方法(行为)来逐步进行晚会。
面向过程的核心概念是函数,以功能为中心,实现了函数级别的代码重用。
面向对象的核心概念是封装了属性和方法(行为)的类,以数据为中心,实现了类级别的代码重用。
面向对象因为采用了类,具有继承和多态特性,可以进一步重用代码和简化编程,而面向过程中没有继承和多态特性。
1.1.2使用面向对象进行设计
下面就开始电子宠物系统的设计和开发之路吧,这一章的任务是用类来描述宠物,然后实现领养宠物功能。
首先需要根据需求进行面向对象的设计。
问题:
我们要设计一个电子宠物系统,其中领养宠物功能的详细需求如下。
根据控制台提示,输入领养宠物的昵称。
根据控制台提示,选择领养宠物的类型,有两种选择:
狗狗和企鹅。
如果类型选择狗狗,要选择狗狗的品种,有两种选择:
“聪明的拉布拉多犬”或者“酷酷的雪纳瑞”。
如果类型选择企鹅,要选择企鹅的性别:
“Q仔”或“Q妹”。
所领养宠物的健康值默认是100,表示非常健康。
所领养宠物和主人的亲密度默认是0,表示和主人还不熟悉。
在控制台打印出宠物信息,包括昵称、健康值、亲密度、品种或性别,表示领养成功。
如何依据需求,使用面向对象思想来设计我们的电子宠物系统呢?
分析
面向对象设计的过程就是抽象的过程,我们分三步来完成。
第一步:
发现类。
第二步:
发现类的属性。
第三步:
发现类的方法。
面向对象设计的过程就是抽象的过程,根据业务需求,关注与业务相关的属性和行为,忽略不必要的属性和行为,由现实世界中“对象”抽象出软件开发中的“对象”,如图1.2所示。
图1.2面向对象设计的过程就是抽象的过程
接下来我们就按照发现类、发现类的属性和发现类的方法的步骤完成设计。
我们可以通过在需求中找出名词的方式确定类的属性,找出动词的方式确定方法。
并根据需求实现业务的相关程度进行筛选。
第一步:
发现类。
需求中名词有控制台、宠物、昵称、狗狗、企鹅、类型、品种、聪明的拉布拉多犬、酷酷的雪纳瑞、性别、Q仔、Q妹、健康值、亲密度和主人等。
根据仔细筛选,发现可以作为类的名词有宠物、狗狗、企鹅和主人。
本章要实现领养宠物功能,主要用到两个类:
狗狗(Dog)和企鹅(Penguin)。
宠物和主人在完善设计和增加功能时再使用。
第二步:
发现类的属性。
需求中动词主要有输入、选择、领养、打印等。
某些明显与设计无关、不重要的词语可以直接忽略。
通过仔细筛选,发现可作为属性的名词有昵称、健康值、亲密度品种和性别,还有一些名词是作为属性值存在的,例如聪明的拉布拉多犬、酷酷的雪纳瑞是品种的属性值,Q仔和Q妹是性别的属性值。
根据需求,定义狗狗类的属性有昵称(name)、健康值(health)、亲密度(love)和品种(strain)。
企鹅类的属性有昵称(name)、健康值(health)、亲密度(love)和性别(sex)。
狗狗和企鹅的某些属性,例如年龄、体重、颜色等与领养业务需求无关,不予设置。
第三步:
发现类的方法。
通过仔细筛选,发现类的方法主要是打印宠物信息。
狗狗和企鹅的方法主要就是打印出自己的信息,取名为print()。
至于狗狗睡觉、洗澡等行为,企鹅吃饭、游泳等行为,与领养业务需求无关,现在先不为其设定方法,在后续业务中若有需求再添加。
设计是一个逐步调整、完善的过程,类图是面向对象设计的“图纸”,使用“图纸”进行设计方便沟通和修改。
将设计的结果通过类图来表示,如图1.3和图1.4所示。
图1.3Dog类图图1.4Penguin类图
小结
抽象时遵循的原则。
属性、方法的设置是为了解决业务问题的。
关注主要属性、方法。
如没有必要,无增加额外的类、属性与方法。
1.2通过创建对象实现领养宠物功能
1.2.1创建类的对象
已经设计出了类及其属性和方法,下面需要把类图表示的内容转变为Java的类代码。
狗狗类的代码如示例1所示。
示例1
/**
*宠物狗狗类。
*@author北大青鸟
*/
publicclassDog{
Stringname=“无名氏”;//昵称,默认值是“无名氏”
inthealth=100;//健康值,默认值是100
intlove=0;//亲密度
Stringstrain=“聪明的拉布拉多犬”;//品种
/**
*输出狗狗信息
*/
publicvoidprint(){
System.out.println(“宠物的自白:
\n我的名字叫”+this.name+”,健康值”+this.health+“,和主人的亲密度是”+this.love+“,我是一只”+this.strain+“。
”);
}
}
企鹅类的代码如示例2所示。
示例2
/**
*宠物企鹅
*@author北大青鸟
*/
publicclassPenguin{
Stringname=“无名氏”;//昵称
inthealth=100;//健康值
intlove=0;//亲密度
Stringsex=“Q仔”;//性别
/**
*输出企鹅信息
*/
publicvoidprint(){
System.out.println(“宠物的自白:
\n我的名字叫”+this.name+”,健康值”+this.health+“,和主人的亲密度是”+this.love+“,性别是”+this.sex+“。
”);
}
}
从示例1和示例2中我们学习了类的基本结构,其主要由属性和行为组成,成为类的成员变量(或者成员属性)和成员方法,同成为类的成员(除此之外,类的成员还包括构造方法、代码块等)。
问题
已经有了狗狗和企鹅类,如何领养宠物呢?
分析
领养宠物的步骤如下
根据控制台提示输入宠物的类型、昵称等内容。
根据输入内容创建相应的宠物对象。
打印出宠物信息表,示领养成功。
通过测试类来创建具体的宠物对象并输出信息,如示例3所示。
示例3
importjava.util.Scanner;
/**
*领养宠物
*@author北大青鸟
*/
publicclassText{
publicstaticvoidmain(String[]args){
Scannerinput=newScanner(System.in);
System.out.println(“欢迎您来到宠物店!
”);
//1.输入宠物名称
System.out.println(“请输入要领养宠物的名字:
”);
Stringname=input.next();
//2.选择宠物
System.out.println(“请选择要领养的宠物类型:
(1.狗狗2.企鹅)”);
switch(input.nextInt()){
case1:
//2.1如果是狗狗
//2.1.1选择狗狗的品种
System.out.println(“请选择狗狗的品种:
(1.聪明的拉布拉多犬”+“2.酷酷的雪纳瑞)”);
Stringstrain=null;
if(input.nextInt()==1){
strain=”聪明的拉布拉多犬”;
}else{
strain=“酷酷的雪纳瑞”;
}
//2.1.2创建狗狗对象并赋值
Dogdog=newDog();
dog.name=name;
dog.strain=strain;
//2.1.3输入狗狗信息
dog.print();
break;
case2:
//2.2如果是企鹅
//2.2.1选择企鹅性别
System.out.println(“请选择企鹅的性别:
(1.Q仔2.Q妹)”);
Stringsex=null;
if(input.nextInt()==1)
sex=”Q仔”;
else
sex=“Q妹”
//2.2.2创建企鹅对象并赋值
Penguinpgn=newPenguin();
pgn.name=name;
pgn.sex=sex;
//2.2.3输出企鹅信息
pgn.print();
}
}
}
运行结果如图1.5和图1.6所示。
图1.5领养狗狗运行结果
图1.6领养企鹅运行结果
从示例3中我们学习了Java中对象的创建和成员的调用方法,语法和C#中是相同的。
通过构造方法来创建对象,例如“Penguinp=newPenguin();”。
通过对象名.属性名的方式调用属性,例如“p.name=”qq”;”。
通过对象名.方法名的方式调用方法,例如“p.print();”。
类(Class)和对象(Object)是面向对象中的两个核心概念。
类是对某一类事物的描述,是抽象的、概念上的定义。
对象是实际存在的该事物的个体,是具体的、现实的。
类和对象就好比模具和铸件的关系,建筑物图纸和建筑物实物的关系。
我们可以由一个类创建多个对象。
示例1是一个Dog类的代码,示例2是一个Penguin类的代码。
但是如果要实现我们的需求,只有类是不行的,还需要创建对应类的实例,也就是对象。
在示例3中我们根据输入的数据创建了宠物对象并输出宠物信息。
规范
类名、属性名、方法名以及常量名的命名规范如下。
类名有一个或几个单词组成,每个单词的第一个字母大写,如Dog、StringBuffer。
属性名和方法名有一个或几个单词组成,第一个单词首字母小写,其他单词首字母大写,例如health、stuName、println()、getMessage()。
常量名由一个或几个单词组成,所有字母大写,如PI、SEX_MALE。
问题
如果我们创建了很多企鹅对象,他们的性别分别取值为“Q仔”或“Q妹”,但是后来要求变化,规定企鹅的性别只能取值“雄”或“雌”,此时已创建的每个企鹅对象的性别都要做相应修改,修改量很大,且代码可能分散在多个文件,不易查找,有没有更好的解决办法呢?
分析
可以定义两个常量SEX_MALE和SEX_FEMAL,分别取值为“Q仔”和“Q妹”,再给企鹅赋值时直接将常量名SEX_MALE或SEX_FEMALE赋值给sex属性。
如果以后要修改sex为“雄”或“雌”时,不管已创建了多少个对象,只需要修改两个常量的值就可以了,这样就方便很多。
finalStringSEX_MALE=“Q仔”:
SEX_MALE是常量,值只能是“Q仔”,但是必须在创建对象后,通过对象名.SEX_MALE方式使用,很不方便。
staticfinalStringSEX_MALE=“Q仔”:
SEX_MALE是常量,值只能是“Q仔”,可以在创建对象后,通过对象名.SEX_MALE方式,也可以直接通过类名.SEX_MALE方式使用,建议采用此种方式。
给企鹅类添加两个静态常量SEX_MALE和SEX_FEMALE,如示例4所示。
示例4
//**
*宠物企鹅类,使用静态常量。
*/
publicclassPenguin{
Stringname=“无名氏”;//昵称
inthealth=100;//健康值
intlove=0;//亲密度
staticfinalStringSEX_MALE=“Q仔”;
staticfinalStringSEX_FEMALE=“Q妹”;
Stringsex=SEX_MALE;//性别
/**
*输入企鹅的信息
*/
publicvoidprint(){
System.out.println(“宠物的自白:
\n我的名字叫”+this.name+“,健康值是”+this.health+“,和主人的亲密度是”+this.love+“,性别是”+this.sex+“。
”);
}
}
编写测试类,创建三个企鹅对象并对其性别赋值,如示例5所示。
示例5
/**
*测试静态常量的使用。
*@author北大青鸟
*/
publicclassText{
publicstaticvoidmain(String[]args){
Penguinpgn=null;
pgn=newPenguin();
System.out.println(“第一个企鹅的性别是”+pgn.sex+“。
”);
pgn.sex=Penguin.SEX_FEMALE;
System.out.println(“第二个企鹅的性别是”+pgn.sex+“。
”);
pgn=newPenguin();
pgn.sex=Penguin.SEX_MALE;
System.out.println(“第三个企鹅的性别是”+pgn.sex+“。
”);
}
}
运行结果如图1.7所示。
图1.7输出企鹅的性别
如果要改变企鹅的性别取值为“雄”和“雌”,只需要修改Penguin类中的两个常量的值即可,如示例6所示,而创建对象的类如示例5所示,不用做任何修改。
示例6
/**
*宠物企鹅类,使用静态常量
*/
publicclassPenguin{
Stringname=“无名氏”;
inthealth=100;
intlove=0;
staticfinalStringSEX_MALE=“雄”;
staticfinalStringSEX_FEMALE=“雌”
Stringsex=SEX_MALE;
/**
*输出企鹅信息
*/
publicvoidprint(){
System.out.println(“宠物的自白:
\n我的名字叫”+this.name+“,健康值是”+this.health+“,和主人的亲密度是”+this.love+“,性别是”+this.sex+“。
”);
}
}
再次运行示例5,运行结果如图1.8所示。
图1.8修改常量值后运行结果
static可以用来修饰属性、方法和代码块。
static修饰的变量属于这个类所有,即由这个类创建的所有对象共用同一个static变量。
通常把static休士顿属性和方法称为类属性(类变量)、类方法。
不使用static修饰的属性和方法,属于单个对象,通常称为实例属性(实例变量)、实例方法。
类属性、类方法可以通过类名和对象名访问,实例属性,实例方法只能通过对象名访问。
final可以用来修饰属性、方法和类。
用final修饰的变量称为常量,其值固定不变。
关于final的具体内容会在第二章详细讲解。
1.2.2构造方法及其重载
问题
在示例3中先创建对象,再给属性赋值,通过多个语句实现。
例如:
Penguinpgn=newPenguin();
pgn.name=name;
pgn.sex=sex;
能不能在创建对象的时候就完成复制操作呢?
分析:
能!
就是通过带参数的构造方法
下面就让我们先认真理解一条熟悉的陌生语句吧。
Penguinpgn=newPenguin();
在Penguin类中增加一个无参的Penguin(),如实例7所示,看看会出现什么情况。
示例7
/**
*宠物企鹅类,测试无参构造方法。
*@author北大青鸟
*/
publicclassPenguin{
Stringname=“无名氏”;
inthealth=100;
intlove=0;
Stringsex=“Q仔”;
/**
*无参数的构造方法
*/
publicPenguin(){
name=“囡囡”;
love=20;
sex=“Q妹”;
System.out.println(“执行构造方法”);
}
/**
*输出企鹅的信息
*/
publicvoidprint(){
System.out..println(“宠物的自白:
\n我的名字叫”+this.name+“,健康值是”+this.health+“,和主人的亲密度是”+this.love+“,性别是”+this.sex+“。
”);
}
/**
*测试无参构造方法的使用
*/
publicstaticvoidmain(String[]args){
Penguinpgn=null;
pgn=newPenguin();
pgn.print();
}
}
运行结果如图1.9所示。
图1.9显示构造方法被执行
其中Penguin()就是Penguin类的构造方法,从执行结果可以看到当执行语句pgn=newPenguin()时就会执行Penguin()中的代码。
没有Penguin()时,系统会提供一个空的penguin()。
构造方法(Constructor)是一个特殊的方法,它用于创建类的对象,因此一个类必须包含至少一个构造方法,否则就无法创建对象。
构造方法的名字和类名相同,没有返回值类型。
构造方法的作用主要就是在创建对象时执行一些初始化操作,如给成员属性赋初值。
让我们通过MyEclipse的断点追踪法来追踪构造方法的执行过程,从而更清楚、更直观的理解该过程。
首先在示例7的main方法的“pgn=newPenguin();”语句来设置断点,然后以调试方式运行该程序,进入调试透视图并在断点处暂停,如图1.10所示。
图1.10构造方法执行过程
(一)
按调试窗口中的单步跳入按钮(或按F5键),进入Penguin类,连续按单步跳过按钮(或按F6键),首先执行Penguin类的属性定义语句一次给各属性赋初值,如图1.11所示。
继续按单步跳过按钮(或按F6键),会一次执行构造方法中的语句,用构造方法中的值替代属性初始值,如图1.12所示。
执行完构造方法内语句后,会跳回到如图1.10所示界面,表示创建对象成功,并把对象引用赋值给变量pgn,至此构造方法执行完毕。
问题:
示例7中通过构造方法完成了对象成员属性的赋值,但属性值已经在构造方法中写死了,能不能在创建对象的时候完成不同属性的动态赋值呢?
分析:
能!
就是通过带参数的构造方法,这就涉及到了构造方法的重载。
为Penguin类增加两个有参的构造方法,如示例8所示。
示例8
/**
*宠物企鹅类,指定多个构造方法
*@author北大青鸟
*/
publicclassPenguin{
Stringname=“无名氏”;
inthealth=100;
intlove=0;
Stringsex=“Q仔”;
/**
*无参构造方法
*/
publicPenguin(){
name=“囡囡”;
love=20;
sex=“Q妹”;
System.out.println(“执行构造方法”);
}
/**
*两个参数构造方法
*/
publicPenguin(Stringname,Stringsex){
this.name=name;
this.sex=sex;
}
/**
*四个参数构造方法
*/
publicPenguin(Stringname,inthealth,intlove,Stringsex){
this.name=name;
this.health=health;
this.love=love;
this.sex=sex;
}
/**
*输出企鹅信息
*/
publicvoidprint(){
System.out.println("宠物的自白:
\n我的名字叫"+this.name+",健康值是"+this.health+",和主人的亲密度是"+this.love+",性别是"+this.sex+"。
");
}
/**
*测试构造方法的使用。
*/
publicstaticvoidmain(String[]args){
Penguinpgn=null;
pgn=newPenguin();
pgn.print();
pgn=newPenguin("亚亚","企鹅");
pgn.print();
pgn=newPenguin("美美",80,20,"Q仔");
pgn.print();
}
}运行结果如图1.13所示。
示例8中共有三个构造方法,方法名相同,参数列表不同,这成为构造方法的重载。
可以通过构造方法重载来实现多种初始化行为,我们在创建对象的时候可以根据需要选择合适的构造方法。
下面我们把示例8中无参数的构造方法注释掉,看看会出现什么情况。
运行结果如图1.14所示。
为什么会出现这个错误呢?
同C#一样,在没有给类提供任何构造方法时,系统会提供一个无参的方法为空的默认构造方法。
一旦提供了自定义构造方法,系统将不会再提供这个默认构造方法。
如果要使用它,程序员必须手动添加。
强烈建议此时为Java类手动提供默认构造方法。
学习了创建对象,如何销毁对象呢?
在Java中,对象