此文记录了咱对 Java OOP 的初步理解
由于是初学,文章也是初写,难免有错误,有的话,请指出
修改记录
- 2020-09-22 原始文章
- 2020-11-01 coding 有了点积累,回来追加一部分内容
前言
利用选择、循环、数组等这部分的内容,我们已经可以解决相当一部分的问题了。而当我们想构建一个包含着文本输入框、按钮等控件的 GUI 应用时,利用前面所学的知识,似乎需要耗费相当大的功夫。
面向对象编程
所以,为了提高软件的灵活性,开发性与可维护性,于是面向对象编程 (Object-Orient Programming) 便出现了,面向对象编程,顾名思义就是使用 Object(对象) 来进行程序设计
对象
什么是对象
那什么东西是 Object 呢?
听到对象这个词语的时候,我下意识看了下自己,咱可没有对象啊
但老师告诉过我们,遇到不懂的词语,就要学会查字典。Object 在字典中的释义是
THING: a solid thing that you can hold, touch, or see but that is not alive
懂了(其实没懂),对象,放在生活上,不就是个具体的物体吗?
那么按理来讲,猫猫狗狗勺子苹果桌子学生,甚至是一个抽象的圆都可以是对象啊
放到计算机语言上,(复制粘贴的)一个可以被明确标识的实体,就是对象,并且每一个对象都偶有自己独特的标识、状态和行为
上面的文字真的好绕啊,理解对象是什么,我觉得最好还是要举栗子
比如,我们现在啥都没有,但是,来 左边 跟我一起画个龙 在你右边 画一道彩虹
于是乎便有了一条龙和一道彩虹
这条龙和这道彩虹,便是对象,龙有着独特位置(左)和长度这些特点,而彩虹也有着独特位置(右)和颜色等这些特点,这些都是用来描述他们的属性的 一个对象具有其独特的 attribute 和 behavior (属性与行为)。 如这条彩虹有着一定的大小与颜色深浅性质,这些都是通过它的 data field 才表示的;而如它的消失便是一个行为,一个对象的行为是通过 method 来定义的
类
什么是类
前面提及了对象,在这个地方说 class 便会自然而然了
来点正经的,先让我们忘掉刚刚那条龙和那一道彩虹(
我们拿正方形和电视机来说事
四条边相等并且互相垂直的四边形,便是正方形,这是每一个正方形基本性质,而对于每一台电视机,都有音量、频道和开关这些属性。 上述这些这些对于每一个正方形或者每一台电视机来说,是共有的。 或是说,每个正方形是同一类东西,每台电视也是如此 所以我们可以通过 class 来生成每一个 object
比如我们可以通过 Square 类来创建三个边长不同的正方形,它们都有着正方形的性质,只是边长不同罢了。这个过程叫做 instantnation(实例化)
Note: instance is equivalent to object 类在 instantnation 的过程中起到了一个相当于“模板”的作用,电视机对象也是如此。
设想: 我是一个电视装配厂的工人,我可以跟着生产指南(class)进行电视机的基本装配,便可以不断装配出数不胜数的电视机。 所以,可把类理解为产出同类对象的基本模板或者蓝图
日后追加部分
2020-11-01 追加部分 可能会对文章逻辑造成影响 推荐跳过这部分的阅读
对上面那句话怎么了解呢,又模板又蓝图的?
经过多一点的实操之后,发现优点不是仅仅万物皆对象,而是让某段代码拥有更好的更强的可复用性,就拿一个实际的音乐播放器类进行举例吧。
如果有两台音乐播放器,我们按照之前的面向过程写法,就是分别声明变量来对应每一播放器的属性,如播放器的开关这个属性,就要声明下面这两个变量
isOn1: boolean isOn2: boolean
并给它们上一个开机关机方法
toggle(isOn: boolean): void
开关机就要这样做
toggle(isOn1);
toogle (isOn2);
那么如果我们要管理 n 台音乐播放器,那么就要手动声明如下变量 isOn1 isOn2 ... isOnn
对他们进行开关机操作就要这样做
toggle (isOn1);
toggle (isOn2);
...
toggle (isOnn);
这臃肿与 coding 效率啊,请自己细品。
所以我们可以对播放器,创建一个 Player 类
public class Player {
private boolean isOn;
public void toggle() {
isOn = !isOn;
}
}
这样一来每一台播放器都有着相同的作用域和方法,开关只需要操作指定的播放器对象即可,如player1.toggle()
追加结束
类里有什么
类包含有什么,能吃吗?类如何定义的,我可以吗?直接看下码
class Square {
/** data field */
double length;
/** constructors */
Square() {
length = 1;
}
Square(double inLength) {
length = inLength;
}
/** methods */
double getArea() {
return length * length;
}
void getLength() {
System.out.println(length);
}
void setLength(double newLength) {
length = newLength;
}
}
我们可以注意到一个 class 里面,包含有data field, constructor, method (好像分别是数据域 构造方法 方法 还是英语顺眼)
在本例中,data field 里面的 length 变量是每一个对象都有且是特有的(称之为 instant variable 实例变量,当然这不包括 static variable),在每一个对象中单独存在且不会相互影响,method 则包含了这个对象特有的方法(当然这也不包括 static method)
然后就是constructor了。我们注意到 constructor 与 construct 有关,那很好理解了(中文好像是构造器吧中文叫构造方法)。constructor 便是新建对象时候所使用的方法。
新建对象
可以如下新建一个 square 对象
Square square1 = new Square();
括号里面可以含actual parameter也可以不含,不含的我们称之为 no-arg constructor .
这上面的语句用到了 new operator, 是不是似曾相识呢?
没错啦,仔细回忆一下 array 和命令行输入的内容?
输出的我们需要新建 Scanner 类下的对象
Scanner input = new Scanner(System.in);
新建数组我们需要的是新建一个 array 对象 (Java 将 array 视为对象看待)
int[] array = new int[10]; //create an array that contains 10 elements
所以,结合之前的一些基础内容,也可以让我们理解创建对象的语句。
试讲 constructor
constructor 嘛,就是用来 construct 对象的,并且 constructor 在 syntax 方面与 method header 极其相像
因为只是极其相像,所以也有几点不像的(?
-
与 method header 相比,没有 return type
-
名字必须与类名 完 全 一 致
-
只在新建对象的时候会用到
如上面的 Square class 中的片段
/** constructors */
Square() {
length = 1;
}
Square(double inLength) {
length = inLength;
}
如果不带参地创建新对象,就会对该对象的 length 变量(instant variable)赋值 1,而如果带实参的话,该对象便会以含形参的 Square(double inLength)的 constructor 进行 construct,此时变量 length 便会以 inLength 赋值
那我忘记了创建 constructor 怎么办?
如果你啥 constructor 也没加的话,恭喜你(?),因为 Java 会 implicitly 帮你加上一个的:ClassName() {}
如果只加了带 argument 的话,no-arg constructor 是不会再帮你加上的了
UML class diagram
我们能以 UML(Unified Modeling Language) class diagram方式表示类与对象
把 Square 类做成图表的话,便会是如下所示
---
| Square |
| ------------------------ |
| length: int |
| |
| Square() |
| Square(inLength: double) |
| getArea(): void |
| getLength(): void |
| ------------------------ |
也就是说用 UML class diagram 进行图示的话,遵从下列规则
Class name | Denoted as |
---|---|
Data Fields | dataFieldName: dataFieldType |
Constructors | ClassName(parameterName: parameterType) |
Methods | methodName(paramterName: parameterType): returnType |
reference variable
那么在面向对象编程中,object variable 和 primitive-type variable 有什么区别呢
请与之前学到的数组建立起联系(数组在 Java 中被当成对象并且我们已经熟知了 Java 数组)
正如我们所知道的,基本数据类型是被存放于 stack 里的,而 object 是被存放在 heap 里面的
面向对象的数据类型不包含 value,而是作为一个 reference 指向目的的对象
由数组说起
试回忆前面 array 内容,array variable 是作为一个 reference variable,被引用到 heap 里相对应的数组
int[] array = new int[10]; // create a new array
/** and array is a reference variable that reference to the array at the heap */
array[0] = 1; // assign 1 to element 0 at array
int[] array1; // create a new array variable called array1
array1 = array; // now array1 has the same reference as array
System.out.println(array[0]); // output: 1
System.out.println(array1[0]); // output is the same: 1
如下图
| stack | | heap |
| | | |
| | | |
| | | |
| | | |
|--------------|reference | |
| main() | to | An array that |
| array | ---------|-->contains 10 elements |
|--------------| | |
以对象结束
那么对于对象来讲,其实跟数组几乎一致(数组也是对象啊喂
Square square1 = new Square(4); // create a square object which has length of 4
Square square2; // create a new reference variable of class Square
square1.getLength(); // output: 4
square2 = square1;
square2.setLength(5); // now make object square's length to 5
square2.getLength(); // output: 5
square1.getLength(); // output: 5
语句 square2 = square1;
把 square2 的引用也指向了 square 对象,正因如此,invoke 的 method 和修改的 data field 都是属于同一个 object 的
可以表示如下
Before square2 = square1
| stack | | heap |
| | | |
| | | |
| | | |
| | | |
| main() |reference | |
| square2 | to | |
| square1 | ---------|--> a square Object |
|--------------| | |
After
| stack | | heap |
| | | |
| | | |
| | | |
| ---|----------|----------------------- |
| main() | |reference | | |
| square2 --- | to | | |
| square1 | ---------|--> a square Object <-- |
|--------------| | |
总之,可以粗略地理解为在 OOP 中的变量其实就像一个书签,没有具体的值,指向着目标对象。
自我总结
其实呢,在学习编程时候,可以进行联系与联想的,这些操作可以使得你有一个具体的认知,并且让前后知识结合得更加紧密,形成一个比较稳健的知识体系
关于文中出现英语的这件事
emm 还有有时候会忍不住用一下英语,是因为嘛,计算机几乎所有内容都是西方世界的,直接使用英语不好过加一步转化成为中文?
比如下面这个例子
这是对总线的解释
总线 是指计算机组件间规范化的交换数据的方式,即以一种通用的方式为各组件提供数据传送和控制逻辑
略有不解?
那好,总线的英语是Bus
既然是 Bus,那他就是计算机部件之间交换数据的方式啊。这不是简单粗暴吗?
所以学习计算机与编程之类的,最好还是要把英语功底加深一下
而如何加深呢?是不是天天百词斩启动,生词背上几十个?(
其实不然,英语是我们生活中的应用工具,编程也如此,不使用它们,它们便会从你的记忆中褪去
附上瞎编的一句话吧
工具 不能纯粹学习 更要学以致用