前言
Java是面向对象的编程语言,那么在开始编写任何代码之前,我们需要学习一些面向对象的基本概念。
本课我们将学习对象、类、继承、接口和包,每个概念都集中讨论这些概念如何与现实世界相关联,同时还介绍一些Java语言的语法。
另外,面向对象不是什么高深莫测的绝世武功,而是人观察世界的一种自然思维,只是绝大多数人从来没有认真思考其本质罢了。
- 万物皆对象
- 万物皆可分类
- 万物皆可命名
- 万物皆可观察
- 万物皆可描述/定义
- 万物皆可创造
- 万物皆可调用
- 万物皆有关系
1、什么是对象?
对象(Object)是相关状态和行为的软件包。计算机软件中的对象通常用于对现实世界中的对象进行建模,因此,对象是理解面向对象技术的关键。那么,状态和行为如何在对象中表示?如何实现数据封装?为什么以这种方式设计软件?
环顾四周,我们会发现许许多多真实世界的事物,比如猫、狗、电脑、自行车、面包和罗汉果等等,它们都是物理对象,因为有都有重量、三维尺寸和体积。除此之外,其它的则是逻辑事物,比如创意、计划、日程表、电子文档等等。
而且,现实世界中的对象有两个共同特征:状态和行为。从面向对象编程的角度出发,识别真实对象的状态和行为是一种很好的方法。
序号 | 对象 | 状态 | 行为 |
---|---|---|---|
01 | 猫 | 名称、颜色、品种、体温 | 抓老鼠、黏人 |
02 | 狗 | 名称、颜色、品种、饥饿 | 吠叫、取物、摇尾巴、看门 |
03 | 电脑 | 品牌、机箱、主板、显卡、键盘 | 启动、关闭、休眠、待机 |
04 | 自行车 | 当前档位、当前踏板节奏、当前速度 | 换档、换踏板节奏、踩刹车 |
05 | 面包 | 重量、颜色 | 饱腹、营养 |
06 | 罗汉果 | 重量、颜色、大小 | 润喉、清肺 |
07 | 警察 | 类别 | 执勤、站岗、调查、抓捕、格斗 |
现在,让我们观察周围的每个对象,问自己两个问题,并把观察结果记录下来。
这个对象可能处于什么状态?
这个对象可能执行什么行为?
当我们这样做时,就会注意到现实世界的对象的有趣之处,这些观察结果都将转化为面向对象编程依据。
复杂性
比如台灯可能只有两种可能的状态(on和off)和两种可能的行为(on、off),但是收音机可能有其他的状态(on、off、current volume、current station)和行为(on、off、increase volume、decrease volume、seek、scan和tune)。所以,我们发现,事物有相似之处,也有差异之处,这将帮助我们如何分类和命名。关系
对象也会包含其他对象,比如台式电脑的主机箱中,还有电源、主板、显卡、内存条等等。除了包含关系外,还有依赖、继承/派生、抽象/泛化、以及实现。
软件对象在概念上与现实世界的对象相似:它们也由状态和相关的行为组成。对象将其状态存储在字段(某些编程语言中的变量)中,并通过方法(某些编程语言中的函数)公开其行为。方法操作对象的内部状态,并充当对象到对象通信的主要机制。隐藏内部状态并要求所有交互都通过对象的方法来执行,这就是所谓的数据封装——面向对象编程的一个基本原则。
以自行车为例:
通过指定状态(当前速度、当前踏板节奏和当前齿轮)并提供改变该状态的方法,对象仍然可以控制外部世界如何使用它。例如,如果自行车只有6个齿轮,那么换齿轮的方法可以拒绝任何小于1或大于6的值。
将代码绑定到单独的软件对象提供了许多好处,包括:
模块化
一个对象的源代码可以独立于其他对象的源代码来编写和维护。一旦创建了对象,就可以很容易地在系统中传递。信息隐藏
通过只与对象的方法交互,其内部实现的细节对外部世界保持隐藏。代码复用
如果一个对象已经存在(可能是由另一个软件开发人员编写的),您可以在程序中使用该对象。这允许专家实现/测试/调试复杂的、特定于任务的对象,然后您可以信任这些对象在您自己的代码中运行。可插拔性和调试简便性
如果某个特定对象出现问题,您可以简单地将其从应用程序中删除,并插入一个不同的对象作为其替代。这类似于解决现实世界中的机械问题。如果一个螺栓坏了,你可以换掉它,而不是整台机器。
2、什么是类?
类是创建对象的蓝图或原型。我们可以定义一个类,对真实对象的状态和行为建模。
在现实世界中,我们经常会发现许多同类的独立物体。世界上可能还有成千上万辆其他的自行车,都是同样的牌子和型号。每一辆自行车都是由同一套蓝图建造而成,因此包含了相同的部件。在面向对象术语中,我们说每一个自行车都是对象,是被称为自行车的类的一个实例。由此可见,类是创建单个对象的蓝图。类泛指同类所有事物,而对象指具体事物。
下面的Bicycle 类是自行车的一个可能实现:
class Bicycle {
int cadence = 0;
int speed = 0;
int gear = 1;
void changeCadence(int newValue) {
cadence = newValue;
}
void changeGear(int newValue) {
gear = newValue;
}
void speedUp(int increment) {
speed = speed + increment;
}
void applyBrakes(int decrement) {
speed = speed - decrement;
}
void printStates() {
System.out.println("cadence:" +
cadence + " speed:" +
speed + " gear:" + gear);
}
}
Java编程语言的语法看起来很新,但是这个类的设计是基于前面对自行车对象的讨论。字段cadence、speed和gear表示对象的状态,而方法(changeCadence、changeGear、speedUp等)定义对象与外部世界的交互。
您可能已经注意到,Bicycle类不包含一个主方法。那是因为它不是一个完整的应用;这只是自行车的蓝图,可能会在应用中使用。创建和使用新的自行车对象的职责属于应用程序中的其他类。
下面是一个创建两个单独的自行车对象并调用它们的方法的脚踏车演示类:
class BicycleDemo {
public static void main(String[] args) {
// Create two different
// Bicycle objects
Bicycle bike1 = new Bicycle();
Bicycle bike2 = new Bicycle();
// Invoke methods on
// those objects
bike1.changeCadence(50);
bike1.speedUp(10);
bike1.changeGear(2);
bike1.printStates();
bike2.changeCadence(50);
bike2.speedUp(10);
bike2.changeGear(2);
bike2.changeCadence(40);
bike2.speedUp(10);
bike2.changeGear(3);
bike2.printStates();
}
}
该测试的输出打印两辆自行车的结束踏板节奏、速度和齿轮:
cadence:50 speed:10 gear:2
cadence:40 speed:20 gear:3
3、什么是继承?
继承为组织和构造软件提供了一种强大而自然的机制。本节我们讨论类如何从它们的超类继承状态和行为,并解释如何使用Java编程语言提供的简单语法从另一个类派生一个类。
不同种类的物体常常有一定数量的共同之处。例如,山地自行车、公路自行车和双人自行车都具有自行车的特点(当前的速度、当前的踏板节奏、当前的档位)。然而,每一辆自行车都定义了使它们与众不同的附加功能:双人自行车有两个座位和两组把手;公路自行车有把手;一些山地自行车有一个额外的链环,给他们一个较低的传动比。
面向对象编程允许类从其他类继承常用的状态和行为。在本例中,自行车现在成为了山地车、公路自行车和TandemBike的超类。在Java编程语言中,每个类都允许有一个直接的超类,而且每个超类可以有无限个子类:
创建子类的语法很简单。在类声明的开头,使用extends关键字,后跟要从其继承的类的名称:
class MountainBike extends Bicycle {
// new fields and methods defining
// a mountain bike would go here
}
这给了MountainBike与Bicycle相同的字段和方法,但允许其代码只关注使其独一无二的特性。这使得子类的代码易于阅读。但是,您必须注意适当地记录每个超类定义的状态和行为,因为这些代码不会出现在每个子类的源文件中。
4、什么是接口?
接口是类与外部世界之间的契约。当一个类实现一个接口时,它承诺提供该接口发布的行为。本节定义了一个简单的接口,并解释了实现它的任何类的必要更改。
正如您已经了解的,对象通过它们公开的方法定义它们与外部世界的交互。方法形成对象与外界的接口;例如,电视机前面的按钮是你和塑料外壳另一边的电线之间的接口。你按下“电源”按钮来打开和关闭电视。
在其最常见的形式中,接口是一组具有空主体的相关方法。自行车的行为,如果指定为接口,可能会出现如下:
interface Bicycle {
// wheel revolutions per minute
void changeCadence(int newValue);
void changeGear(int newValue);
void speedUp(int increment);
void applyBrakes(int decrement);
}
要实现这个接口,您的类的名称将会更改(例如,更改为特定品牌的自行车,例如ACMEBicycle),并且您将在类声明中使用implements关键字:
class ACMEBicycle implements Bicycle {
int cadence = 0;
int speed = 0;
int gear = 1;
// The compiler will now require that methods
// changeCadence, changeGear, speedUp, and applyBrakes
// all be implemented. Compilation will fail if those
// methods are missing from this class.
void changeCadence(int newValue) {
cadence = newValue;
}
void changeGear(int newValue) {
gear = newValue;
}
void speedUp(int increment) {
speed = speed + increment;
}
void applyBrakes(int decrement) {
speed = speed - decrement;
}
void printStates() {
System.out.println("cadence:" +
cadence + " speed:" +
speed + " gear:" + gear);
}
}
实现接口允许类对其承诺提供的行为更加正式。接口在类和外部世界之间形成一种契约,编译器在构建时强制执行这种契约。如果您的类声明要实现一个接口,则由该接口定义的所有方法必须出现在其源代码中,然后该类才能成功编译。
要实际编译ACMEBicycle类,您需要将public关键字添加到实现的接口方法的开头。稍后在关于类、对象、接口和继承的课程中,您将了解造成这种情况的原因。
5、什么是包?
包是一个以逻辑方式组织类和接口的名称空间。将代码放到包中使大型软件项目更容易管理。本节解释为什么这很有用,并向您介绍Java平台提供的应用程序编程接口(API)。
包是组织一组相关类和接口的名称空间。从概念上讲,您可以认为包类似于计算机上的不同文件夹。您可以在一个文件夹中保存HTML页面,在另一个文件夹中保存图像,在另一个文件夹中保存脚本或应用程序。因为用Java编程语言编写的软件可以由数百或数千个单独的类组成,所以通过将相关的类和接口放入包中来保持组织是有意义的。
Java平台提供了一个巨大的类库(一组包),适合在您自己的应用程序中使用。这个库被称为“应用程序编程接口”,简称为“API”。它的包表示与通用编程最相关的任务。例如,一个字符串对象包含字符串的状态和行为;文件对象允许程序员轻松地创建、删除、检查、比较或修改文件系统上的文件;套接字对象允许创建和使用网络套接字;各种GUI对象、控制按钮和复选框以及任何与图形用户界面相关的东西。有成千上万的类可供选择。这样,作为程序员的您就可以将重点放在特定应用程序的设计上,而不是放在使其工作所需的基础设施上。
Java平台API规范包含Java SE平台提供的所有包、接口、类、字段和方法的完整清单。在浏览器中加载该页面并将其添加到书签中。作为一名程序员,它将成为您最重要的参考文档。
6、OOA&D
--
7、编程的本质
如果你面对一个问题域,一开始就着手编写代码,那么,这是舍本逐末、缘木求鱼的行为!原因如下:
计算机不会思考,编程的本质在于用计算机理解的语言告诉其具体怎么做。从这个角度上将,编程是在为自己的大脑编程。
面向对象分析、设计和编程,是一种观察、分析和思考事物复杂性及关系的方法论,上述过程都可以在大脑中完成,编程只是按部就班搬砖的后向性动作。
持续更新,欢迎留言提议!
码字很累,多点赞多赞赏!