You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

606 lines
26 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

## 1. 什么是面向对象?
对象Object这个概念广泛存在于我们的生活当中一般只一个独立的个体具备一定的特性properties并有一定的动作能力capability。例如一个具体的人具备属性性别、年龄、升高...);同时具备一定的能力(说话、跑步、工作...
面向对象编程是指把相关数据和函数按照对象的方式进行组织和分类以便达到便于设计、实现、维护和增加代码重用率的目的。面向对象编程中的类Class与对象Object与我们常用语境中的概念有所不同我们在学习的过程中注意区分。
下面用一个例子来说明面向对象编程的基本思想。
### 1.1. 用C来描述一个对象
我们以一个简单的例子来分析面向对象这个例子是描述平面中的一个圆。这里我们需要两组参数来描述圆第一个参数是坐标位置X、Y另外一个是圆本生的描述例如大小半径r可能还有颜色等等简单来说我们目前只有半径。
如果从C语言出发需要建立一个结构体来描述圆。
```c
struct Circle
{
float x; // X坐标
float y; // Y坐标
float r; // 半径
};
```
上面只是定义了一个结构体抽象代表所有圆但是还不存在一个真正的圆的实例具体的对象因此需要定义一个变量其类型是Circle这个结构体。
```c
struct Circle c1;
```
如果要改变c1这个圆结构变量的值我们有两种方法首先是直接赋值。
```c
struct Circle c1;
c1.x = 0;
c1.y = 1;
c1.r = 11.2;
```
**这里通过点(.)这个限定符来区分结构体变量和结构体内的成员**
另外还可以用函数的方式来改变结构体的值。
```c
/**
* 给圆设定初始值
* @param c 圆结构的指针
* @param x 坐标X
* @param y 坐标Y
* @param r 半径R
*/
void setCircle(struct Circle *c, float x, float y, float r) {
c->x = x;
c->y = y;
c->r = r;
}
```
另外我们一次性的打印整个圆的数据,这样我们最好需要一个函数。
```c
/**
* 打印
* @param c
*/
void printCircle(struct Circle *c) {
printf("The position x=%f, y=%f, radius=%f!\n", c->x, c->y, c->r);
}
```
把所有代码放在一起:
```c
#include <stdio.h>
#include <malloc.h>
struct Circle {
int x;
int y;
float r;
};
/**
* 给圆设定初始值
* @param c 圆结构的指针
* @param x 坐标X
* @param y 坐标Y
* @param r 半径R
*/
void setCircle(struct Circle *c, int x, int y, float r) {
c->x = x;
c->y = y;
c->r = r;
}
/**
* 打印
* @param c
*/
void printCircle(struct Circle *c) {
printf("The position x=%d, y=%d, radius=%f!\n", c->x, c->y, c->r);
}
int main() {
struct Circle *c1;
c1 = (struct Circle *) malloc(sizeof(struct Circle));
c1->x = 0;
c1->y = 1;
c1->r = 11.2;
printCircle(c1);
setCircle(c1, 1, 1, 3.3);
printCircle(c1);
return 0;
}
```
### 1.2. C语言描述圆的总结
1. 圆的结构体描述是一个抽象的描述因为结构体是类型定义并没有与其对应的变量这儿描述和后面的Java类的定义很像。
2. 声明一个结构体变量后就有一个真实的内存变量来描述一个特定的圆了这个变量是圆抽象描述的一个实例实体也叫做对象这个概念和Java的对象非常相似
3. 通过点(.)或者(->)可以操作结构体变量对象内部的成员这点和Java对象的操作也非常相识只不过Java都是用点(.)
这里我们发现,操作结构体的函数是独立定义的,并且需要把结构体变量作为参数进行传递。圆这个结构体是死的,需要外部的函数来对其进行操作。如果把圆这个结构体变量和生活中的对象联系起来,会有些有趣的事情。
例如,人这个对象有固有的特性(性别、年龄、身高、体重。。。)这些和圆的坐标和半径对应,都表示一个对象的特性;但是人可以说话,可以运动(动作、行为,相当于函数);而结构体变量的圆不能自己动作,只能依靠外部的函数进行动作。如果圆可以自己动作,例如让圆这个对象自己打印输出,这样不就可以和生活中的对象联系起来了?
```c
struct Circle
{
float x; // X坐标
float y; // Y坐标
float r; // 半径
function void print(){
printf("The position x=%f, y=%f, radius=%f!\n", x, y, r);
}
};
struct Circle c1;
c1.print(); // C语言无法做到
```
如果要实现上面的功能显然C是不能做到的需要有更先进的语言例如C++或者是Java。
抽象来说,对象是一组相关数据以及在这些相关数据上操作函数的集合。
如果把结构体进行扩展使其可以包含数据和函数那么这个结构体就变成了面向对象中的类或者对象了。扩展结构体这个事情交给C++来完成我们需要学习一个更友好、更方便的面向对象语言JavaC++对于大多人来说太难了Java会简单许多。
当然面向对象不止有扩展结构体这样简单的功能,还需要学到相关的继承、多态、接口等高级特性,用来简化代码的编写。
### 1.3. 使用Java来实现
接下来我们使用java来实现上述的功能这里主要是要把相关的函数作为结构体的一个部分。
```c
/**
* 定义Circle类
*
* @author danny
*
*/
class Circle {
float x;
float y;
float r;
public void setCircle(float x, float y, float r) {
this.x = x;
this.y = y;
this.r = r;
}
public void printCircle() {
System.out.printf("The position x=%f, y=%f, radius=%f!\n", x, y, r);
}
}
/**
* 主类,主函数
*
* @author danny
*
*/
public class Circle_Test {
public static void main(String[] args) {
Circle circle = new Circle();
circle.x=0;
circle.y=1;
circle.r=11.2F;
circle.printCircle();
circle.setCircle(1, 1, 3.3F);
circle.printCircle();
}
}
```
看有什么区别?
1. Java定义一个类是如何的
2. Java中1316行中的this代表什么
3. Java的语法和C有什么区别
4. 注意C中33行和Java中32行代码代表什么意思
5. 注意C中给结构体指针成员赋值与Java中对象成员赋值的区别。
6. Java中类包含了函数这是C中结构体不具备的能力。
7. C和Java都有主函数Main他们的写法有什么不一样
#### 1.3.1. 编译和运行Java
把Java代码保存到Circle_Test.java的文件名中。
命令行中执行:
```bash
javac Circle_Test.java
```
发现生成了两个文件
![](img/20230302094127.png)
这两个class文件是java编译后的文件类似Windows中的exe文件。但是这个文件不能直接运行需要在Java虚拟机VirtualMachine中运行。
接下来使用命令行
```bash
java Circle_Test
```
运行刚刚编译后的代码,得到结果
```bash
The position x=0, y=1, radius=11.200000!
The position x=1, y=1, radius=3.300000!
```
这个结果和C的结果是一致的。
**文件名必须是 Circle_Test.java这个文件名的主文件名必须和源文件中 public class Circle_Test {...} 的类名保持一致。**
**javac是编译命令java是运行命令使用java虚拟机运行编译后的代码。关于虚拟机下面会讲到。**
## 2. JAVA的特点和历史
### 2.1. Java虚拟机
在我们学习Java之前先来看看程序应用是如何运行的。
广义上来说程序是运行在CPU上的一段二进制代码。为了使得CPU等硬件资源可以得到统一的管理一般来说我们需要一个操作系统OS。大多的应用程序Application都运行在操作系统上这样多个程序可以在操作系统的协调下充分使用CPU等硬件的资源。当然也有不需要操作系统的例如嵌入式控制器MCU上面的很多程序因为功能简单也不需要操作系统。
常见的操作系统有WindowslinuxMac OSAndroid等。不同操作系统上面的应用程序一般是不能互换的。即使同一种操作系统上面的程序因为CPU的架构Architecture不同也不能互换。例如Linux可以运行在X86Intel/AMD的通用CPU属于这个架构架构上也可以运行在ARM大多移动设备的CPU架构上。但是一个为X86上Linux编译的应用程序一般情况下并不能运行在ARM上的Linux系统中也有例外例如Java的应用或者是有些跨平台的编程语言。一般来说我们把CPU架构和操作系统的整体称作平台Platform
以前我们学过的C语言是一种静态编程语言关于静态和动态编程语言的概念我们在后面讲解需要一个编译链接过程后形成一个可执行文件这个可执行文件就是通常所说的应用。如果你在Windows上面编译的C语言程序显然是不能运行在Linux系统当中的因为平台不一样。但是通常我们可以把源代码在目标平台上进行编译、链接可能需要适当的源代码调整使其可以在不同的平台上面运行。源代码这种可以通过少量修改的方法可以在不同平台下面运行的特性叫做可移植性。显然C语言是源代码级别的可移植。要做到编译后程序可以在不同的平台上运行就更好了比如我们学过的Java就可以做到因为Java不是直接在操作系统上面运行而是在Java虚拟机上运行。Java虚拟机保证了所以编译好的Java代码都可以其上运行而不用关心其平台是否一样。
好了,我们看到了一般的程序是如何运行的,如下图。
![Alt text](img/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.drawio.svg)
这种分层的设计理念我们在很多地方都用到例如网络的TCP/IP协议层软件系统当中的分层设计。分层的设计的目的就是为上层提供统一且稳定的服务而隔离下层的不同。从上图知如果操作系统是Windows无论硬件是Intel还是AMD上层的应用都可以不做修改的运行当然CPU架API: application programming interface JDK: Java Developing Kit IDE: Integrated Development Environment 构需要一致。而Java的高明之处就在于Java自己有虚拟机屏蔽了所有下层的不同只要是Java的应用在有Java虚拟机的平台上都可以运行。
### 2.2. Java的编译和运行
![](img/20230302095100.png)
**bytecode是java编译后的二进制代码只能在java虚拟机上运行。**
### 2.3. 基本概念
**The Java Language Specification, API, JDK, and IDE**
#### 2.3.1. JDK、API、IDE
1. API: application programming interface应用编程接口。Java提供了一套最基本的类包括文件操作、网络操作、数学运算、输出输出、数据结构等用来简化你的开发。这些其实是最基本的数据结构和操作函数只不过Java是按照类class的方式来组织类比C语言中的标准函数库是按照头文件和C文件来组织的。
2. JDK: Java Developing Kit是Java的开发套件。类比C语言可以看作是编译器、链接器这些命令行工具。不同的是Java没有链接只有编译工具Javac另外Java编译后的代码.class文件有叫做bytecode不能直接运行需要使用java虚拟机java运行。
3. IDE: Integrated Development Environment这是集成开发环境。一般人不会用写字板和命令行行Jdk来开发Java因为效率太低了。 
## 3. JAVA开发环境
使用命令行和文本编辑器也可以编辑和运行Java但是效率很低因此我们需要一个集成开发环境IDE Integrated Development Environment来编辑、运行和调试Java代码。
常用的IDE有 EclipsenetbeansIntelliJ IDEA 等。其中最强大的是 IntelliJ IDEA但是其是收费的有免费社区版本为了统一我们使用开源免费的 Eclipse 来作为我们学习的 IDE。
**你可以使用任何IDE来开发Java但是考试的时候只提供 Eclipse。因此掌握Eclipse是必须的。**
### 3.1. 安装
Eclipse 是一个开放的框架基于Eclipse框架的有很多不同语言的IDE包括C、PHP、Python等我们只需要下载Java的IDE就可以了。访问 [Eclipse 官方网站](https://www.eclipse.org/downloads/packages/) ,下载 "Eclipse IDE for Java Developers";你需要根据你的平台来选择。
**最新的Eclipse已经自带了JDK不需要单独下载JDK。**
解压缩后双击eclipse.exe 就可以运行。
### 3.2. 运行
启动Eclipse出现一个Workspace工作空间的选择。工作空间是一个目录Eclipse在这个目录中可以建立多个项目Project每个项目可以包含多个java源代码文件。Eclipse在每次运行的时候会让你选择Workspace这样Workspace->Project->Source code 就是Eclipse管理源代码的层级关系。
![](img/20230302095429.png)
**请选择一个你方便管理的目录作为Eclipse的Workspace这个目录路径最好不要包括中文或者是特殊字符。**
第一次打开空的Workspace会出现一个欢迎的界面关闭就可以了。
![](img/20230302095510.png)
除了菜单、工具条Eclipse大约分为上述4个区间。
#### 3.2.1. 新建项目
在左边有"Create a Java project"的快捷方式新建一个项目也可以在File->New菜单中找到新建项目的功能。
![](img/20230302095541.png)
在弹出的对话框中主要是:
1. Project name项目名称建议使用英文命名规则可以参考C语言的变量命名规则
2. Use an execution environment JREJava虚拟机的版本请一定选择1.8这个版本因为我们书中的例子是按照1.8版本的。
**项目名称最好使用英文符合C语言变量名命名规则。因为项目名称直接对应到Workspace文件夹中的一个子文件夹中文可能会造成意想不到的问题。**
**在开发过程中请记住不要使用中文来命名任何的名称保持C语言变量名规则是一个好策略。例如一般只有注解、需要输出或者是显示的地方使用中文。**
生成项目后的界面如下:
![](img/20230302095621.png)
这个界面中项目名称不用说了JRE System Library 是虚拟机提供的库类似C语言中提供的标准库文件、算术、网络库等这些库中的类C语言中是头文件是可以在我们源代码中引用的src是一个特殊的文件夹所有的Java源代码必须在这个文件夹中。
#### 3.2.2. Hello world
我们建立一个简单的Hello world 程序,这里会使用到包的概念。
对于简单的程序可能一个源文件就可以了例如编写一个Hello world的代码。但是对于复杂的应用一个文件显然有很多缺点为什么考虑一下C语言是如何管理多个源代码的工程的
把一个复杂的工程拆分成多个小的代码片段可以便于工程项目的管理与维护当然编译速度也会加快。但如果所有源代码放在一个文件夹中还是非常混乱因此Java引入了Package的概念。我们先界面左边src上单击鼠标右键在菜单中选择New->Package新建一个包。
![](img/20230302095647.png)
源代码位置一般不要轻易修改,只需要填写包名。
**注意这里又是名称,记住我们上面的规则**
![](img/20230302095710.png)
现在左边src下面多了一个first的包。现在鼠标右键单击first菜单中选择New->Class
![](img/20230302095740.png)
1. Name类名上面名称的规则。在Java中一个类**一般**是一个文件一个文件可以包含多个类一般不建议。一个类的定义如同C中结构体类型的定义。Java推荐类名的首字母大写
2. Modifiers可视等级这个以后解释这里选择 public 就可以了;
3. Superclass父类这个以后解释保持缺省
4. public static void main(String[] args)如果C语言需要一个main的主函数作为启动入口如果你需要请勾选会自动给你建立一个空的main函数。因为我们需要这个类可以运行因此勾选。
完成后,会打开一个新的类:
```java
package first;
public class Hello {
public static void main(String[] args) {
// TODO Auto-generated method stub
}
}
```
接下来我们修改这个类框架主要是修改main函数部分结果如下
```java
package first;
public class Hello {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
```
保存ctl+s可以运行看看结果
![](img/20230302095908.png)
#### 3.2.3. 包和源文件结构
![](img/20230302095923.png)
我们看看文件系统中的情况,如上图。包其实对应到的就是文件夹。当然一个包中可以再包含子包,如果一个文件夹中可以包含子文件夹一样。
**类名永远是和文件名对应的类名是Hello对应的文件就是Hello.java**
注意,源代码的第一行是:
```java
package first;
```
表明了这个文件是属于哪个包的那么可以在src下面建立一个类吗答案是可以的不过这里不用新建我们使用鼠标在左边的工程列表中把已经建立好的Hello.java拖动到src目录这个位置Eclipse会新建一个同名的文件。但是这个文件在哪里
![](img/20230302100019.png)
这个文件并不在src文件夹中而在一个叫做 default package 的包中,我们打开这个文件:
```java
public class Hello {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
```
注意,第一行并没有 package 这个申明。在看看文件系统:
![](img/20230302100109.png)
Hello.java 这个文件的确在src文件夹中。
**src文件夹中的类文件的package可以不用写代表在缺省包中也就是src这个文件夹中。**
**如果需要改变源文件的位置请在Eclipse中的项目管理中进行支持文件的复制、移动、删除等操作。Eclipse始终会保持源代码中的package申明的正确性。这个功能其实在高级的IDE中叫做重构Refactor重构还有很多应用例如批量修改函数名、变量名等功能可以在菜单 Refactor 中找到更多的功能。**
### 3.3. Java代码结构
总的来说Java是一种类C的语言基本语法和C十分相似。例如函数、变量名命名规则代码块判断、选择语句循环语句注解等都保持和C一致。
我们再来回顾以下上面最简单的Hello world
```java
package first;
public class Hello {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}
```
1. package包描述该源代码在那个包对应src文件夹中的字文件夹。如果有多个层级的包src子文件夹中的子文件夹使用点.来分割包名。尝试一下在包下面建立子包后package是如何描述的。package不是必须的如果java文件在src中package可以省略这时表示缺省包。
2. 一般来说一个Java文件包含一个类Class结构如果有多个并列的Class结构只能有一个描述成public。关于public的含义后面会讲到。
3. 类名或者描述成public的类名这个例子是Hello必须和主文件名一致。
4. Java中的变量、常量、函数等结构都属于一个类Class在类外面定义非类Class的结构都是非法的。
5. 如果要代码运行需要一个主函数main且这个函数的写法是固定的上面代码第5行且main函数所在的类必须是public修饰的。
6. 一个工程中可以有多个类多个主函数这个和C是有区别的。C中一个工程只能有一个主函数。
后续的学习中会学到更多关于语法方面的内容,这里只做一个初步的了解。
#### 3.3.1. 关于指针
这里讨论指针比较早C中的指针是一个非常重要的概念在Java中关于类似C指针的概念有区别这里需要进行说明请大家先有个印象。
1. 首先Java中不存在C中指针的术语与之对应的是引用reference。引用和指针其实是相似的
2. Java中有动态分配内存如使用 new 操作符但是不需要回收Java虚拟机会自动回收
关于引用的具体内容我们放在函数和类中进行讲解。
## 4. 错误类型
错误类型包含三种Syntax Errors、Runtime Errors、Logic Errors。
### 4.1. Syntax Errors
语法错误,编译的时候发现,例如:
```java
public class ShowSyntaxErrors {
public static main(String[] args) {
System.out.println("Welcome to Java);
}
}
```
### 4.2. Runtime Errors
运行时错误运行时产生的错误例如空对象操作、0作为除数、文件不存在等。运行时错误是我们需要特别关注的因为会导致程序的流程异常产生意想不到的结果。例如下面这个例子
```java
public class ShowRuntimeErrors {
public static void main(String[] args) {
System.out.println(1 / 0);
}
}
```
运行时错误也叫做异常Exception后面会专门讲到异常处理。
### 4.3. Logic Errors
逻辑错误,简单说来就是语法没错、也没有运行时错误(异常),但是结果错误了。通常是编程者的算法错了,例如:
```java
public class ShowLogicErrors {
public static void main(String[] args) {
System.out.println("Celsius 35 is Fahrenheit degree ");
System.out.println((9 / 5) * 35 + 32);
}
}
```
你认为上面代码的结果是什么?
### 4.4. Debug
**debug功能非常重要虽然考试不会直接考但是debug会极大的加快编码调试的效率请同学们一定重视。**
基本的调试非常简单,就只有端点设置与变量查看,再掌握几个快捷键会提升你调试的效率。下面我们在缺省包的位置建立一个简单的循环打印代码来演示调试的技术。
代码如下:
```java
public class Debug {
public static void main(String[] args) {
String outStr = "";
for (int i = 0; i < 10; i++) {
outStr += i + ",";
System.out.println(outStr);
}
}
}
```
输出结果是:
```{.line-numbers}
0,
0,1,
0,1,2,
0,1,2,3,
0,1,2,3,4,
0,1,2,3,4,5,
0,1,2,3,4,5,6,
0,1,2,3,4,5,6,7,
0,1,2,3,4,5,6,7,8,
0,1,2,3,4,5,6,7,8,9,
```
#### 4.4.1. 设置中断
![](img/20230302100434.png)
在需要中断(程序会在进入这一行之前暂停)的源代码行号前面双击,会出现一个蓝色的点,表示中断以及设置成功,接下来点击调试按钮就可以让程序运行,并且在设置中断的地方暂停。
#### 4.4.2. 调试界面
eclipse的调试界面是单独的布局第一次运行调试会提示进入调试界面单击switch按钮就可以了。运行调试后出现下面的界面
![](img/20230302100457.png)
1. 中断行:高亮显示,表示当前需要执行的行(还未执行);
2. 调试窗口:当前的变量值;断电设置;表达式计算等;
3. 输出窗口:和运行是一样的,不过这个输出要更具代码的具体执行位置进行输出;
4. 运行按钮:控制代码执行的按钮:
1. Step overF6单步执行跳过运行到当前下一行代码如果有函数不进入函数
2. Step intoF5如果高亮代码有函数进入函数执行单步执行
3. Step returnF7从函数中返回到被调用位置单步执行
4. ResumeF8执行直到下一个个中断位置
5. TerminateCtl+F2终止运行无论是否运行完成立即终止并退出。
尝试不断按F8观察调试窗口、输出窗口的变化。
**在代码编辑区域,用鼠标指向变量,会显示变量的当前值。**
**调试还有很多高级功能,例如条件中断(在一个断点上设置一定的条件,不是每次都中断;表达式计算等等),大家可以尝试一下。用好调试工具可以极大提升学习的效率。**
**当程序成功运行并退出Terminate按钮会变成灰色如果是红色表示程序仍然在运行。**
调试完成后可能你想要回到以前的编程视图这时需要单击右上角的视图切换Perspective
![](img/20230302100555.png)
## 5. 小技巧
为了方便我们的编程,以下两个小技巧是最常用到的。
### 5.1. 让Eclipse任何时候都进行提示代码补全
代码补全是一个非常好用的工具当你输入一个字母的时候IDE会给你提示这样可以加快编码同时减少出错。可是缺省情况下Eclipse只在键盘输入点.)的时候进行代码提示。如果需要输入任何字母的情况下提示,可以按照以下方法进行设置。
菜单Window->Preference 打开Eclipse偏好设置如下图找到Java->Editor->Content Assist在右边的这个地方点的后面输入26个英文字母小写即可点击 Apply and Close 就可以了。
![](img/20230302100616.png)
### 5.2. 代码格式化
菜单 Souorce->Format 或者快捷键 Ctl+Shift+F ,可以使当前代码快速美化。漂亮的代码缩进和编码规则会让代码更容易阅读。
**不同系统下 Eclipse 的快捷键可能并不相同注意参考你自己Eclipse的快捷键。**
## 6. 本章节重点
1. JDK、API、IDE: P11-1.6
2. Java语言的基本结构P12-1.7
3. 建立、编译、执行JavaP15-1.8
4. 错误类型P20-1.10
补充内容:
1. 包和文件夹的关系;不考,但是掌握后有帮助。
2. Eclipse的使用特别是调试Debug不考但是非常有用。