23计科六班 眭世忠 202302151298
这一篇博客是关于的是对于Java面向对象程序设计综合的复习总结,在未来我也会一直在我的博客上记录我的学习过程和心得,达到勉励自己的效果。
第一章 初识java与面向对象程序设计
在这一章呢主要介绍的是编程语言的发展史,java的特点和跨平台的原理,面向对象程序设计思想,Java环境的搭建和第一个Java、程序,以及使用集成工具进行Java的编写。
1.1 Java的概述
1.1.1计算机编程语言发展史
自从冯.诺依曼的理论的提出后,计算机语言在那么多年的发展下,也经历了三个发展阶段:机器语言、汇编语言、高级语言。
第一代计算机进行编程的语言就是机器语言,使用机器语言进行编程的时候,需要用到大量"0"和"1"进行编程。虽然进行编程的时候有迹可寻,但是还是避免不了大量的背诵,而且还需要程序员要会熟练与运用设备。
第二代计算机的编程语言是汇编语言。汇编语言在机器语言的基础上做了一次重大的改革创新。汇编语言与机器语言的区别在于,前者使用了英文单词进行编写,大大减小了程序员开发的难度。可是因为各个平台对于编程语言没有统一的规范,还是要求程序员要熟练的掌握硬件的知识。
第三代计算机编程语言是高级语言。高级语言的面世,可以说的上是"计算机语言的革命",它运用了近乎自然语言和数学公式的编程方式,使得编程难度直线降低。在这之后越来越多人从事计算机软件的开发工作,计算机从而蓬勃发展。
计算机编程语言发展历程如图1.1所示。
图1.1 计算机编程语言发展历程
1.1.2 Java语言发展史
-
起源与早期发展
- 1991年:James Gosling带领Sun Microsystems团队开始开发Java,项目名为“Green Project”。
- 1995年:Java 1.0正式发布,标志着Java语言的诞生。Java具有跨平台性,能够在不同操作系统上运行,这一特性得益于Java虚拟机(JVM)的引入。
-
重要版本更新
- 1996年:发布Java 1.0的重要更新,引入事件模型和AWT图形库。
- 1998年:Java 2发布,引入Java虚拟机(JVM)、Java标准版(Java SE)、企业版(Java EE)和微型版(Java ME)等版本。
- 2004年:Java 5.0(J2SE 5.0)发布,引入泛型、枚举类型等。
- 2006年:Sun发布Java SE 6,增强对Web服务的支持和JVM性能。
- 2009年:Oracle收购Sun Microsystems,成为Java的新所有者。
- 2014年:Java 8发布,引入Lambda表达式、函数式接口和新的日期/时间API。
- 2017年:Java 9引入模块化系统。
- 2018年:Java 10和Java 11发布,引入新特性和性能改进。
-
现代应用与持续发展
- Java在企业级应用、移动应用(特别是Android开发)、Web开发和大数据处理等领域占据重要地位。
图 1.2 Java语言发展历史图
- Java在企业级应用、移动应用(特别是Android开发)、Web开发和大数据处理等领域占据重要地位。
1.1.3 Java语言的特点
- 跨平台性:Java程序可以在不同操作系统上运行,得益于JVM的引入。
- 面向对象:Java支持面向对象的编程范式。
- 强类型:提供严格的类型检查和类型推断。
- 垃圾回收:具有自动内存管理和垃圾回收功能。
- 多线程支持:内置多线程支持,便于并发编程。
- 生态系统丰富:拥有庞大的类库和工具集。
- 安全性高:提供安全管理机制和沙箱模型。
1.1.4 java跨平台原理
-
Java源代码编译:
- Java源代码(.java文件)首先被编译成字节码(.class文件)。
- 字节码是一种与平台无关的二进制格式。
-
Java虚拟机(JVM):
- JVM是Java程序运行的环境。
- JVM负责将字节码解释成特定平台的机器码。
- 不同操作系统需要安装对应版本的JVM。
-
跨平台实现:
- 由于字节码与平台无关,只要安装了JVM,Java程序即可运行。
- 这实现了“一次编译,到处运行”的跨平台特性。
延展
- 查询建议:若需深入了解JVM的内部机制,可查询“Java虚拟机工作原理”。
- 思考方向:思考Java跨平台性对其他编程语言的影响及其在行业中的应用。
java跨平台原理如图1.3所示。
图 1.3 Java跨平台原理图
1.2 面向对象设计思想
1.2.1 面向过程程序设计
面向过程是一种以过程为中心的编程范式,注重解决问题的步骤和流程,关注数据的处理和操作。在面向过程的设计中,程序被分解为一系列的步骤和函数,通过顺序执行这些步骤来完成任务。程序单位主要是过程或函数,由赋值语句、条件语句、循环语句、过程调用语句组成。
面向过程编程通常采用函数作为程序的基本单元,通过函数之间的调用来实现程序的功能。面向过程具有相对简单和直观、易于理解和实现的特点。对于简单的问题和小规模程序,面向过程编程具有高效性和执行速度优势,更加灵活,可以通过过程的组合和调用来构建更复杂的功能。
然而,面向过程也存在明显的缺点,主要是缺乏模块化和封装性,难以重用和维护。由于数据与处理数据的过程分离为相对独立的实体,当数据结构发生改变时,所有与之相关的过程都要进行相应的修改,导致开发和维护困难,且容易造成代码冗余和可扩展性差。
1.2.2 面向对象程序设计
面向对象程序设计(OOP)是以对象为中心,是一种新型的程序设计方法。在面向对象的设计中,重点在于对象的抽象、封装和继承,通过对象之间的交互来解决问题。对象是由数据和对数据的操作行为组成的一个相互依存、不可分割的整体,具有唯一对象名和固定对外接口的一组属性和操作的集合。
面向对象编程强调将问题抽象成对象,每个对象都有自己的状态和行为,并通过相互之间的消息传递来实现协作。面向对象提供了更高层次的抽象和封装,使代码更易于理解和维护。同时,支持代码的重用和模块化,提高开发效率。通过继承和多态性实现代码的灵活性和可扩展性。
面向对象具有封装性、抽象性、继承性和多态性等特性。封装将对象的属性和操作结合成一个不可分割的独立的单位,并尽可能的隐藏对象的内部实现细节,只保留有限的对外接口,解决了面向过程程序设计中数据与操作分离的问题,提高了程序的可复用性和可维护性。
1.2.3 面向过程程序设计与面向对象程序设计的区别
面向过程和面向对象是两种不同的程序设计思想,它们在编程范式、关注点、代码结构、可重用性、可维护性等方面存在显著的差异。
- 编程范式:面向过程以过程(函数)为中心,关注解决问题的步骤和流程;面向对象以对象为中心,关注对象的抽象、封装和继承。
- 关注点:面向过程注重数据的处理和操作;面向对象注重对象的属性和行为,以及对象之间的交互。
- 代码结构:面向过程的代码结构相对简单,但缺乏模块化和封装性;面向对象的代码结构更加复杂,但提供了更高的抽象层次和封装性。
- 可重用性:面向过程的代码重用性较差,因为数据和操作分离,修改数据结构需要修改所有相关过程;面向对象的代码重用性较高,因为对象封装了数据和行为,可以通过继承和多态性实现代码的重用。
- 可维护性:面向过程的代码可维护性较差,因为缺乏封装性,修改一个部分可能影响其他部分;面向对象的代码可维护性较高,因为封装了内部实现细节,只通过对外接口进行交互,降低了模块之间的耦合度。
1.3 第一个java程序:"HelloWorld!"
1.3.1 编写代码
在idea中新建一个项目,在项目中编写以下代码。
public class HelloWorld{
public static void main(String[] args){
System.out.printlf("HelloWorld!");
}
}
当你编写完这一段代码,就代表你已经已经进入了java的编程的大门,可是现在你并不知道它们代表着什么,接下来我会详细分析它。
1.3.2 代码解析
代码解析如图1.4所示。
图1.4 代码解析
• public class 是Java 中的两个关键字,用于声明这是一个公共的类,将在面向对象章节详细介绍。
•HelloWorld 是这个类的主类名,主类名必须与文件名完全一致(区分大小写),这里你可以随意修改,只要保证与文件名一致即可。
• public static void main是Java 的mainC)方法。main()方法是程序的入口,它有固定的书写格式,一个字母都不能出错。
• StringL] args 是 main()方法的参数,其中 args 是参数名,参数名称可以随意修改,但这对于 main()方法而言是没有意义的。
• System.out.println("")是输出语句,需要输出的文本内容放人英文双引号内,执行这条语句后就会输出对应的文本。如果想输出其他文本,只修改双引号内的文本内容即可。
编写代码时,需要注意以下书写规范。
•类名的首字母大写,单词之间的第一个字母也需要大写,这称作驼峰规则。
•类名只能由数字、字母、下画线、美元符号$组成,并且第一个字符不能是数字。因为类名要与文件名一致,因此文件名也需要遵循这个规则。
•一个Java 源文件中至多只有一个类能用public 声明,并且 public修饰的类必须和文件名保持一致。
•花括号用于划分程序的各个部分,方法和类的代码都必须以“{”开始,以“}”结束。
•代码中的每条语句以英文的分号“;”结束。
• Java 代码对字母大小写敏感,如果出现了大小写拼写错误,程序无法运行(例如 string)。
为了让代码尽量少出错,应当养成“《}”成对编程的习惯,即如果需要用花括号,先将左右两个花括号写完,再往花括号内填充内容,分号、圆括号同理。同时,注意缩进,每个花括号内的代码都需要有缩进,缩进一般使用键盘上的Tab键。
1.3.3 代码的注释
当我们进行编程的时候免不了会与他人合作或者是一段时间没有运行过一段复杂的代码,在这样的情况下我们就要通过注释的方法达到能让他人或自己快速了解代码的意思,提高可阅读性。
Java中的注释分为单行注释、多行注释和文档注释三种。
(1)单行注释:单行注释使用“//”来表示,它放在该行代码的开头。
(2)多行注释:多行注释使用“/*”开头,以”*/“结尾,在它们之中的内容全是注释。
(3)文档注释:以“/**”开头,以“*/”结尾,其中可以包括一些说明性文字和代码。
1.4 本章小结
这一章是学习java的入门开始,它对整个计算机语言的发展历史进行了简述,并且将java和其他的语言进行了对比,突出了java的特点。还进入了编写第一个java代码的环节,简要的讲述了代码中细节和规范。随后还引入了注释的重要性。
第二章 java编程基础
这一章主要介绍java中的变量和常量、运算符与表达式、选择结构与循环结构、方法与数组,以及jvm中的堆栈内存等编程基础知识。
2.1 变量和常量
2.1.1 关键字和保留字
在我们编写的helloworld的程序中,public、void和class这些都是关键字。关键字在java中是预先定义好的,它是有特殊一样的单词,它们组成了java语言的核心部分。不过正因为它们已经有了自己的实际意义,所以我们不能在定义类名、变量名等时候使用它们。
Java的关键字和保留字如表2.1所示。
表2.1 Java的关键字和表达字
2.1.2 标识符与命名规范
标识符是给java类、方法、变量、包命名的符号。标识符需要遵守一定的规则。
(1)标识符只能由字母、数字、下画线、美元符号组成,并且不能以数字开头。
(2) Java 标识符大小写敏感,长度无限制。
(3) 标识符不可以是Java关键字和保留字。
在这些规则的基础上,每种标识符也都有自己的命名规范,这些将在后面介绍。
2.1.3 数据类型
java是一种强类型语言,每一个变量都需要指定的数据类型。而在java中类型分为基本数据类型和引用数据类型。如图2.1所示。
图2.1 java数据结构
2.1.4 变量的定义和赋值
变量的本质可以用一间房间进行解释,房间号就是变量的名字,房间的类型就是变量的类型,而入住的客人就是变量的值。
变量要先声明再使用,声明的方法如下。
//声明一个变量
数据类型 变量名;
//一次声明多个变量
数据类型 变量1,变量2....;
注意:在同一个代码块中,已经使用过的变量名不能重复使用,声明变量之后还需要赋值,才可以使用,赋值用“=”。赋值的类型与变量的类型要一致。
下面定义一些变量,之后输出变量的值,如代码清单2.1所示。
import java.util.Scanner;
public class ssz {
public static void main(String[] args) {
int num=10;
double num2=3.14;
long num3=100L;
float num4=3.14f;
char num5='A';
Scanner sc=new Scanner(System.in);
System.out.println(num);
System.out.println(num2);
System.out.println(num3);
System.out.println(num4);
System.out.println(num5);
}
}
程序(代码清单2.1)运行结果如图2.2所示。
图2.2 程序运行结果
变量的值是可以重复改变的,变量的命名需要遵守小字母开头的驼峰规则。
2.1.5 常量
常量与变量的区别就是,在变量声明前加上final关键字,而且常量一旦赋值后就不能改变了。常量的命名要求所有字母大写,单词之间用“-”隔开。
2.1.6 变量的类型转换
java的数据类型转换主要分为两种:自动类型转换(隐式转换)和强制类型转换(显式转换)。
首先是自动类型转换,在Java 中,占用字节数少的数据类型的值可以直接赋值给占用字节数多的数据类型的变量,比如 short类型的值可以直接赋值给int 类型的变量,或者int 类型的值赋值给 double 类型的变量,如下所示。
int num1=10;
double num2 =num1;
其中有个特例:int 类型的常量可以直接赋值给char、short、byte,只要不超过它们能表示的值的范围即可。
而强制类型转换则可以强制性地将占用字节数多的数据类型的数据转换成占用字节少的数据类型的数据,但这个转换过程可能存在数据精度丢失的问题。强制类型转换的话法格式如下。
数据类型 变量名=(数据类型)变量值;
2.1.7 Scanner的使用
当我们需要编写一些交互性的程序时,我们就需要使用到Scanner类。Scanner类在Java.util包下,当我们需要到它时,我们要进行导包,不过在新版的idea中程序会自动的导包。使用Scanner的代码,如代码清单2.2所示。
import java.util.Scanner;
public class ssz {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String s = sc.next();
System.out.println("你输入的字符串为:"+s);
System.out.println("请输入一个整数:");
int n = sc.nextInt();
System.out.println("你输入的整数为:"+n);
}
}
程序(代码清单2.2)运行结果如图2.3所示。

2.3 选择结构
2.3.1 if语句
从结构化程序设计角度出发,Java 有三种结构:顺序结构、选择结构、循环结构。
Java 的基本结构就是顺序结构,除非特别指明,否则就按照顺序从上往下一句一句行。顺序结构是最简单的算法结构,语句与语句之间,框与框之间是按从上到下的顺序进的。顺序结构不必做过多说明,前面的程序都是顺序结构。
选择结构用于在代码中做一些逻辑判断,当满足某些条件时,执行某段代码。if语向是选择结构的代表。通过if语句,能够实现各种各样的逻辑判断。if语句的语法格式如下所示。
if(条件表达式1){
代码块1;
}else if(条件表达式2){
代码块2;
}else(){
代码块n;
}
程序执行到 if语句后会进行判断:当条件表达式1为 true 时,执行代码块1;否则,条件表达式2为 true时,执行代码块 2;否则,当条件表达式3为 true 时,执行代码块 3;否则执行代码块n。其中,一个i语句之后可以有0至多个 else if 语句,可以有0或1个 else 语句 。
接下来编写一个对分数进行判断的交互性程序,如代码清单2.3所示。
import java.util.Scanner;
public class ssz {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入学生成绩");
double a = sc.nextDouble();
if (a>100){
System.out.println("分数不合法");
}else if (a>=90&&a<=100){
System.out.println("学生分数为:"+a+"优秀");
} else if (a>=80&&a<=90){
System.out.println("学生分数为:"+a+"良好");
}else if (a>=60&&a<=80){
System.out.println("学生分数为:"+a+"及格");
}else {
System.out.println("学生分数为:不及格");
}
}
}
程序(代码清单2.3)运行结果如图2.4所示。

if语句在使用过程中还需要注意以下两点。
(1)如果i选择结构只需执行一条语句,那么可以省略{}。为了提高代码的易读性,建
议不省略{}。
(2) {}中的代码语句也称为代码块,在代码块定义的常量或变量的作用域仅限于代码
块中,在代码块之外不能使用。
2.3.2 switch语句
switch语句也是选择结构 ,不过它一般会用于一些精准值的判断,其语法格式如下所示。
switch(变量){
case 值1:
代码块;
break;
case 值2:
代码块;
break;
default:
代码块;
break;
}
switch 语句会根据表达式的值从相匹配的case 标签处开始执行,一直执行到 break 语
旬处或者 switch 语句的末尾。如果 case 全都不匹配,则进入default 语句。
接下来编写一个简单的加减乘除计算器。用户输入两个数字和计算符号,根据计算符
号决定执行加法、减法、乘法、除法运算,如代码清单2.4所示。
import java.util.Scanner;
public class ssz {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入运算表达式,数字和符号之间用空格隔开");
int number = sc.nextInt();
char operator = sc.next().charAt(0);
int number1 = sc.nextInt();
switch (operator) {
case '+':
System.out.println(number1 +'+'+ number+'='+(number1 + number));
break;
case '-':
System.out.println(number1 +'-'+ number+'='+(number1 - number));
break;
case '*':
System.out.println(number1 +'*'+ number+'='+(number1 * number));
break;
case '/':
System.out.println(number1 +'/'+ number+'='+(number1 / number));
break;
default:
System.out.println("不合法");
break;
}
}
}
switch语句判断的变量中,类型只能是byte、short、int、char、string(JDK1.7)和枚举,因此它的适用范围较窄,但对于精准值的判断,switch依然是非常方便的。
2.3.3 选择结构的嵌套
选择结构在使用上可以嵌套,if中的代码也可以是switch,switch语句里面也可以是if语句。通过嵌套可以完成更复杂的要求。
2.4 循环结构
2.4.1 for语句
循环结构是Java三大结构之一,它可以在满足一定条件下一直运行程序,从而简短代码。
for是最常见的循环结构,他的语法格式如下。
for(循环初始化表达式;循环条件表达式;循环后的操作表达式){
//循环体
}
首先执行一次循环初始化表达式,接着判断循环条件表达式,如果为false则结束循环。如果 true,则执行循环体,之后执行循环后的操作表达式,重复以上操作,直到表达式的值为false 为止。
接下来编写程序,输出1~1000既能被5整除又能被3整除的数,并且每行输出5个,如代码清单2.5所示。
public class ssz {
public static void main(String[] args) {
int count=0;
for (int i = 1; i <=1000 ; i++) {
if (i%5==0 && i%3==0) {
System.out.println(i+"\t");
count++;
if (count==5) {
System.out.println();
count=0;
}
}
}
}
}
程序(代码清单2.5)运行如图2.5所示。

2.4.2 while 语句
while 语句相较于for循环更简单,它的语法格式有点类似于if语句,如下。
while(条件表达式){
//循环
}
while语句的执行规则也很简单,只要条件表达式的值为turn,就会执行循环体,直到条件表达式的值为false时才退出循环。while一般用于不确定循环次数的场景。
接下来编写程序,找出前10个既能被7整除又能被11整除的数字,如代码清单2.6所示。
public class ssz {
public static void main(String[] args) {
int count=0;
int num=11;
while (count<10) {
if (num%7==0&&num%11==0) {
System.out.println(num);
count++;
}
num++;
}
}
}
程序(代码清单2.6)运行如图2.6所示。

2.4.3 do...while循环语句
不管是for循环还是while循环,都会在循环之前判断循环条件,如果条件刚开始就为false,那么循环体就不会被执行。实际开发中,可能存在需要循环体至少执行一次的场景,此时就可以使用do…while循环语句。语句的语法格式如下所示。
do{
//循环体
}while(条件表达式);
首先执行循环体,之后再判断条件表达式,如果结果为 true,就重复上述步骤,直到条件表达式的值为false 为止。do•while 语句的语法比较简单,但需要注意的细节是条件表达式最后有一个分号。
下面编写程序模拟登录,用户名为 admin,密码为123456,如果用户输入的用户名和密
码不匹配,就重新登录,直到用户名和密码完全匹配为止,如代码清单 2.7所示。
public class ssz {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
String uername;
String password;
do {
System.out.print("请输入用户名: ");
uername = sc.next();
System.out.println("请输入密码");
password = sc.next();
}while (!"admin".equals(uername) || !"123456".equals(password));
System.out.println("登录成功");
}
}
程序(代码清单2.7)运行如图2.7所示。

2.4.4 break和continue语句
在任何循环语句的主体部分,均可用break控制循环的流程。break用于强行退出循环,不执行循环中剩余的语句。而continue则终止某次循环,继续下一次循环。
编写三人一组余两人,五人一组余三人,七人一组余四人,且不为奇数的程序,计算最少需要多少人,如代码清单2.8所示。
public class ssz {
public static void main(String[] args) {
int num=0;
while (true){
num++;
if(num%2==1){
continue;
}
if(num%3==2&&num%5==3&&num%7==4){
System.out.println("至少要"+num+"人");
break;
}
}
}
}
程序(代码清单2.8)运行如图2.8所示。

总结
在这第二章中,我们主要学习了变量和常量,选择结构和循环结构。
在变量和常量中我认为要注意命名规范和类型转换,在初学编程的同学很容易就会忽略这些小细节,往往因为这些问题而出现的报错,同学们很难快速的反应过来。
在选择结构和循环结构中:我认为要多去亲手写代码,在实践中加深对于它们理解,方便我们日后更得心应手的使用
第三章 面向对象程序设计(基础)
3.1 面向对象的概念
3.1.1 面向对象的特性
面向对象具有抽象、封装、继承、多态的特性,更符合程序设计中“高内聚、低耦合”的主旨,其编写的代码的可维护性、可读性、复用性、可扩展性远比面向过程思想编写的代码强,但是性能相比面向过程要偏低一些。
封装、继承、多态是面向对象的三大特性,这是任何一门面向对象编程语言都要具备的。
• 封装:指隐藏对象的属性和实现细节,仅对外提供公共的访问方式。
•继承:继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例属性和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
•多态:指的是同一个方法调用,由于对象不同可能会有不同的行为。
3.1.2类和对象
从编程的角度来说,万物皆对象,可以理解为,现实中存在的任何一个具体的事物都是
一个对象,如一张桌子、一个人、一支笔。
而将现实中一类事物抽象化,提取出这一类事物共有的属性和行为,就形成了类。
3.2面向对象编程
3.2.1类的定义
Java使用class关键字定义一个类。一个java文件可以有很多个类,但是有public修饰的类只能有一个,且这个类还必须与文件名一致,也要遵守大写字母开头的驼峰命名规则。
下面的代码就是创建类的代码。
public class DemObject{
}
class Entity1{
}
class Entity2{
}
上面创造的三个类是空白的类,当我们要开始用到它们时,我们需要在里面添加我们所需的代码块,才能发挥它的作用。
下面的代码创建了一个Student类,有name和age变量,以及eat()和study()方法,如代码清单3.1所示。
public class Student {
public static void main(String[] args) {
String name;
int age;
void study(){
System.out.println(name+"年龄"+age+"岁,在学习");
}
}
}
在成员方法中,可以随意访问类中定义的成员变量。
3.2.2 对象的创建与使用
要创建对象,必须先有一个类,然后通过new关键字创建一个对象。对象创建的语法格式如下。
类名称 对象名称 = new 类名称();
接下来通过代码清单3.2创建两个Student对象,代码如下所示。
public class Student {
public static void main(String[] args) {
Student student = new Student();
student.age = 18;
student.name="张三";
Student student1 = new Student();
student.age = 20;
student.name="李四";
}
}
3.3 构造方法
3.3.1 什么是构造方法
构造方法也称作构造器(constructor),用于给对象进行初始化操作,即对象成员变量赋初始值。构造方法的名称必须与类型相同,并且不能定义返回值,不能出现 return 关键字。构造方法的调用必须通过 new 关键字调用,语法格式如下所示。
修饰符 类名(形参列表){}
事实上,3.2节说到对象创建方式时,提到的“new类名()”是不准确的,准确的说法应
该是使用new 关键字调用它的构造方法。
3.3.2 构造方法的使用
Java 中要求每一个类必须有构造方法,当不在类中定义构造方法时,编译器会自动类提供一个默认的无参数构造方法,一般简称为“无参构造方法”。前面通过 new 关键字建 Student 对象时,就是在调用它默认的无参构造方法。可以在 out 文件夹中找到 Studerclass 文件。
如果手动为其提供了构造方法,那么编译器就不会再为该类型提供默认构造方法了,下面来给Student分别提供无参构造方法和有参构造方法,如下代码所示。
public class Student {
public Student() {
System.out.println("无参构造执行了");
}
public Student(String stuName, int stuAge) {
name = stuName;
age =stuAge;
System.out.println("无参构造执行了");
}
当为类构造了有参和无参的构造方法,可以同时用两种构造方法创建对象。
总结
在第三章中,我们重点要学习类和构造方法的使用,知道它们的格式,以及它们该怎么用。通过本章的学习,我们可以掌握面向对象程序设计的基本思想,并且能够运用面对对象程序设计的思想解决一些实际问题。
第4章 面向对象程序设计(进阶)
4.1 封装
4.1.1 什么是封装
前面提到过,面向对象编程有三大特性:封装、继承、多态,而所谓的封装是什么呢?
要看电视,只需要按一下开关和换台就可以了,不需要了解电视的内部构造,也不需要了解每个开关是如何运作的;要开车,只需要知道哪个是油门,哪个是刹车,怎样转向,至于为什么方向盘能转向,同样不需要知道。厂家为了方便人们使用电视、汽车,把复杂的内部细节全部封装起来,只暴露简单的接口,如电源开关。具体内部是怎么实现的,不需要操心。需要让用户知道的才暴露出来,不需要让用户知道的全部隐藏起来,这就是封装。从
Java 面向对象程序设计的角度上分析,封装是指隐藏对象的属性和实现细节,仅对外提供公共的访问方式。
封装能够在一定程度上提高代码的安全性和复用性,使用时只需要了解使用方式,不需
要知道内部细节。
4.1.2 访问修饰符
在学习封装之前,需要了解访问修饰符。访问修饰符可以修饰类、接口、变量、方法,用于控制它们的访问权限。通过访问修饰符,可以灵活控制哪些细节需要封装,哪些细节需要封装,哪些细节需要对外暴露。
Java 中的访问修饰符有4个,分别为 private、默认(无修饰符)、protected、public。每个
修饰符的访问权限如下所示。
•private:表示私有的,被它修饰的方法、变量只能被当前类访问,因此也称作类可见性。
。无修饰符,表示默认的,被它修饰的方法、变量只能被当前包下飽类访问,因此也称
作包可见性。
•protected:表示受保护的,被它修饰的方法、变量可以被当前包下所有的类,以及其他包下的子类访问到,因此也称作子类可见性。
•Public:表示公开的,被它修饰的方法、变量可以被当前项目下所有的类访问,因此也称作项目可见性。
4.1.3 get()和set()方法
将变量私有化,取而代之的是提供一的Public 的方法,用于给变量赋值或者获取变量,这些方法一般称为“get ()方法(getter)”“set()方法(setter)”。其中,get()方法用于获取值,set()方法用于赋值。
get()方法和 set()方法的命名是有要求的,比如 get()方法,方法名必须以 get 开头面跟对应变量的变量名,并将变量名首字母大写。接下来创建 Student 类,拥有姓名和年变量,并为其提供 get()和 set()方法,如下所示。
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String stuName, int stuAge) {
name = stuName;
age =stuAge;
System.out.println("无参构造执行了");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
if (age < 0) {
age = 0;
}
if (age > 200) {
age = 200;
}
this.age = age;
}
通过get()方法获取变量的值,通过set()方法为变量赋值,这样就是对一个变量的一个简单的封装。
4.2 继承
4.2.1 什么是继承
在现实生活中,继承一般指子女继承父辈的财产。在程序中,继承描述的是事物之间的
所属关系,通过继承可以使多种事物之间形成一种关系体系。
在Java 中,继承使用 extends 关键字。从英文字面意思理解,extends 的意思是“扩展”,即继承是在现有类的基础之上构建出的一个新类,现有类被称作父类(也称作超类、基类等),新类称为子类(派生类),子类拥有父类所有的属性和方法,并且还可以拥有自己独特的属性和方法。
4.2.2 继承的使用
java中使用extends关键字表示继承,语法格式如下表示。
class 父类{
}
class 子类 extends 父类{
}
注意:Java 中类之间只有单继承,因此一个子类只能有一个直接父类。但是Java 支持多层继承,即A类继承B类,B类还可以继承C类,此时C类称A类的间接父类。此外,如果一个类没有继承任何类,那么它会默认继承 java.lang.Object。在Java 中,Object类是所有类的父类,也就是说Java 的所有类都继承了 Object 类,子类可以使用Object 类的所有方法 。
4.3 多态
4.3.1 什么是多态
多态是面向对象的三大特性之一,指的是同一个方法调用,电于对象不同可能会有不同的行为。多态的前提是必须存在继承,并且子类准写广父类的方法,最重要的一点是父类引用要指向子类对象。
何为父类引用指向子类对象呢?比如上面的案例中,Teacher 类和 Worker 类继承自
People 类,那么当创建 Teacher 类对象或者 Worker类对象时,是可以使用 People 类型的变量接收的,如下所示。
People people = new Teacher () ;
这样的好处是,如果一个方法需要接收的参数类型是 People,那么实际调用该方法时可以传入 People 类和它的任意子类对象,从而提高代码的复用性。此外,如果一个方法的返回值是People,那么也可以返回 People类或它的任意子类对象。
4.3.2 多态的实现
多态的实现主要表现在父类和继承该父类的一个或多个子类对某些方法的重写,多个子类对同一方法的重写可以表现出不同的行为。下面以垃圾分类为例,垃圾(Rubbish)分为干垃圾(Dry Rubbish)、湿垃圾(Wet Rubbish)、可回收垃圾(Recyclable Rubbish)和有害垃圾(Harmful Rubbish),其中在垃圾类中拥有分类方法,它的子类都重写了该方法,如下所示。
public class Rubbish {
public void classify(){
System.out.println("垃圾分类");
}
}
public class DryRubbish extends Rubbish{
@Override
public void classify(){
System.out.println("干垃圾");
}
public void showInfo(){
System.out.println("干垃圾分类完可以直接扔");
}
public class WetRubbish extends Rubbish{
@Override
public void classify(){
System.out.println("湿垃圾");
}
}
public class RecyclableRubbish extends Rubbish{
@Override
public void classify(){
System.out.println("可回收垃圾");
}
public void handle(){
System.out.println("可回收垃圾可以变废为宝");
}
public class HarmfulRubbish extends Rubbish{
@Override
public void classify(){
System.out.println("干垃圾");
}
public void handle(){
System.out.println("干垃圾分类完可以直接扔");
}
}
通过多态,代码可以变得更加通用,这也是设计多态的目的。
4.3.3 引用类型数据转换
引用数据类型也存在着类型转换,与其说是类型转换,不如说是转换一个对象的引用。引用类型数据转换分为以下两种。
向上转型:父类引用指向子类对象,属于自动类型转换。格式:
父类类型 变量名 = 子类对象
向下转型:子类引用指向父类对象,属于强制类型转换。格式:
子类类型 变量名 = (子类对象)父类对象
多态实际上就是引用类型向上转型的案例。向上隐藏了子类类型,提高了代码的可拓展性,可以使一个方法的参数能够传入某个类的任意子类对象,但是多态会导致程序只能使用父类的共性内容,不能调用子类特有的方法。
总结
本章是Java 面向对象程序设计的重点,因此用大量篇幅介绍。熟悉面向对象的基础之
后,学习本章的高级特性并不会太吃力。
本章以面向对象的三大特性:封装、继承、多态为核心,介绍了很多知识点,这些知识点
都是为这三大特性服务的。
首先,介绍了访问修饰符和 get()、set()方法的使用,从而将变量进行了封装,使外界无法直接访问变量,取而代之的则是提供了公共的访问方法,从而保障了变量的安全性。接着,介绍了继承,使类与类之间存在了一定的联系,为后面的多态打下了基础。在继承中,变量和方法的访向不同,通过一个内存图解介绍了 super关键字的使用。接着介绍了 final关键字和 Object 类,并对继承进行了详细介绍。
之后以前面的知识点为基础,介绍了多态特性,并通过抽象类、接口的使用,使程序的扩展性、复用性更强。事实上,抽象类、接口、内部类都是为多态服务的,通过合理使用多态,可以让程序的耦合性更小,代码更易扩展。最后,指出了本章中的一些知识点可融人的思政元素。
通过本章的学习,读者能够理解面向对象的三大特性,掌握面向对象高级特性的使用,
并能够编写出具有高复用性和可扩展性的代码。
第5章 异常
5.1 异常概述
5.1.1 什么是异常
生活中经常会遇到一些不正常的现象,比如人会生病、机器会坏、计算机会死机等。而你写的代码也并不是完美的,比如要读取一个文件,如果这个文件不存在该怎么办,如果这个文件不可读又该怎么办,等等。程序在运行过程中可能出现的这些不正常现象就称作异常。异常(Exception),意思是例外,怎么让写的程序做出合理的处理,安全地退出,而不至于程序崩溃。
Java 是采用面向对象的方式处理异常的。当程序出现问题时,就会创建异常类对象并抛出异常相关的信息(如异常出现的位置、原因等),从而能够更迅速地定位到问题原因。
5.1.2异常与错误
·异常与错误是很容易混淆的两个概念,异常指的是程序运行过程中出现的不正常现象,比如文件读不到、链接打不开,影响了正常的程序执行流程,但不至于程序崩溃,这些情况对于程序员而言是可以处理的。而错误则是程序脱离了程序员的控制,一般指程序运行时遇到的硬件或操作系统的错误,如内存溢出、不能读取硬盘分区、硬件驱动错误等。错误是致命的,将导致程序无法运行,同时也是程序本身不能处理的。
比如代码清单 5.1就分别演示了异常和错误的区别。
public class Ssz {
public static void main(String[] args) {
int num=3/0;
int[] arr=new int[1024*1024*1024];
}
}
分别运行异常和错误的两行代码,程序(代码清单5.1)运行结果如图5.1所示。

5.2 异常处理
5.2.1 抛出异常
编写程序时,需要考虑程序可能出现的各种问题,比如编写一个方法,对于方法中的多数就需要进行一定程度的校验。如果参数校验通不过,需要告诉调用者问题原因所在,达时候就需要抛出异常。
Java 中提供了一个 throw 关键字,该关键字用于抛出异常。Java 中的异常本质上也是类,抛出异常时,实际上是抛出一个异常的对象,并提供异常文本给调用者,最后结束该方法的运行。抛出异常的语法格式如下。
throw new 异常名称(参数列表);
5.2.2 声明异常
可以看到,当参数通不过校验时,就会执行抛出异常的代码,并且提示文本也是在代码
中定义好的。
程序仅仅抛出异常,而不对异常进行处理,是没有任何意义的,但处理异常之前,需要知道调用的方法可能会抛出哪些异常,从而有针对性地处理。因此,需要将异常声明到方法上,让调用者知道这个方法可能会抛出什么异常。
声明异常使用 throws 关键字(与throw 非常像,需要注意),语法格式如下。
修饰符 返回值类型 方法名(参数列表)throws 异常类名1,异常类名2,⋯
其中,如果方法中抛出的是运行时异常,编译期就不会强制要求开发者将异常声明在方法上,而如果抛出的是编译时异常,则必须将这些异常全部声明在方法上。
5.2.3 捕获异常
如果程序出现了异常,自己又解决不了,就需要将异常声明出来,交给调用者处理。上面已经将异常进行了声明,此时调用者如果已经知道被调用方法可能出现哪些异常,就可以针对这些异常进行不同的处理。
处理异常使用 try•catch•finally结构,try 用于包裹住可能出现异常的代码块,在catch 中进行异常捕获,并处理异常,finally则是在抛出异常或者异常处理后执行。当异常不进行处理时,发生异常的方法就会立即结束运行,而如果使用try⋯catch 处理,程序就会继续运行下去。接下来再对上面的代码进行修改,对两个异常进行处理。
5.3 异常进阶
5.3.1 自定义异常
尽管 Java 中已经定义了大量的异常,但实际开发中这些异常并不能完全涵盖所有的业
务场景,不能通过异常文本判断业务逻辑问题所在。
例如,登录场景中,绝大乡数网站为了防止暴力撞库,对于用户不存在和密码错澳两和场景的提示文本都是“用户名或密码错误”,这是为了防止不法分子根据提示文本而推断出网站的用户。
但是,对于开发者而言,需要在日志中能够区分某个“用户名或密码错误”究竟是用户不存在,还是密码错误,此时就需要 UserNotFoundException 和 Password WrongException 两个异常。很明显,Java 中不可能事先定义好这些异常,因此就需要用户自定义一些与业务场景相关的异常。
自定义异常语法很简单,就是创建一个类并继承 Exception 或者 RuntimeException,提
供相应的构造方法,如下所示。
修饰符 class 自定义异常名 extends Exception 或 RuntimeBxception {
public自定义异常名(){//默认调用父类无参构造方法}
public自定义异常名(String msg){//调用父类具有异常信息的构造方法
super (msg) ;}
}
5.3.2 方法重写的异常
当一个类的方法声明了一个编译时异常后,它的子类如果重写该方法,重写方法声明的异常不能超过父类的异常,这里只遵循如下两点即可。运行时异常不受这两点约束。
(1)父类方法没有声明异常,子类重写该方法不能声明异常,如下所示。
class Parent {
public void method1 ( ) {}}
class Child extends Parent {
//编译错误
@ Override
public void methodl () throws Exception {}}
(2)父类方法声明了异常,子类重写该方法可以不声明异常,或者只声明父类的异常
该异常的子类,如下所示。
class Parent {
public void method]() throws IOException {}}
class Child extends Parent {
//编译错误
@ Override
public void methodi () throws FileNotFoundException {}}
总结
本章主要介绍了异常的使用。首先对异常的概念和体系进行了介绍,通过继承关系讲述了异常的分类,以及异常与错误的区别。然后介绍了异常的抛出、声明、捕获,要求开发者对能够预知到的异常必须进行处理。接着介绍了自定义异常,开发者可以尽可能地根据业务场景定义出对应的异常,从而便于在生产环境中排查错误。最后指出了本章中的一些知识点可融人的思政元素。
我认为在这一章节中,只需要了解异常代表了什么,已经在后续使用的时候能知道怎么正确的使用就好了,这一章还是很好理解的。
第6章 java常用类
6.1 包装类
6.1.1 什么是包装类
Java 是面向对象的语言,但并不是纯面向对象的语言,比如Java 中的基本数据类型就不是对象。然而,在实际开发中,要求“一切皆对象”,基本数据类型很多场景下满足不了使用,比如一个 App 注册阶段,年龄是非必填项,当用户不填时,在系统中应当如何表示?可能有人认为,使用。表示未填写,但实际上0岁与未填写是两码事,基本数据类型 int 就表示不出这种“未填写”的状态。
为了解决这种问题,让基本数据类型也可以像对象一样进行操作,在设计类时为每个基本数据类型设计了一个对应的类,这样,与这8个基本数据类型对应的类统称为包装类
(Wrapper Class) .
包装类都在java.lang 包下。包装类与基本数据类型的对应关系如表6.1 所示。
表6.1 包装类与基本数据类型的对应关系
这8个类中,除 Character 和 Integer 外,其余6个包装类其实都是对应基本数据类型的首字母大写,非常方便记忆。其中,除 Character 和 Boolean外,其余的类都继承自 Number 类,称为数值类。数值类中都重写了 Number 的6个抽象方法:byte Value ()、Shor Yalue(),intValue()、,long Value()、HloatValue().doubleValue(),这意味着6 个数值类之同可以互相转换。
包装类的主要作用如下。
(1)让基本数据类型可以像对象一样进行操作,提供了更多方便的方法。
(2)提供了null值,让基本数据类型可以表示“未填写”的状态。
6.1.2 基本数据类型与包装类
各种包装类的使用方式基本类似,这里以 Integer 类为例。Integer 类中提供了大量字
符串-包装类-基本类型之间进行转换的方法。 下面通过代码清单6.1,演示以上方法的使用。
public class ConversionExample {
public static void main(String[] args) {
// 基本类型到字符串的转换
int primitiveInt = 123;
String stringFromInt = intToString(primitiveInt);
System.out.println("基本类型到字符串: " + stringFromInt);
// 字符串到基本类型的转换
String string = "456";
int intFromString = stringToInt(string);
System.out.println("字符串到基本类型: " + intFromString);
// 基本类型到包装类的转换
Integer wrapperInt = intToWrapperInt(primitiveInt);
System.out.println("基本类型到包装类: " + wrapperInt);
// 包装类到基本类型的转换
int primitiveIntFromWrapper = wrapperIntToInt(wrapperInt);
System.out.println("包装类到基本类型: " + primitiveIntFromWrapper);
// 包装类到字符串的转换
String stringFromWrapper = wrapperToString(wrapperInt);
System.out.println("包装类到字符串: " + stringFromWrapper);
// 字符串到包装类的转换
Integer wrapperFromIntString = stringToWrapperInt(string);
System.out.println("字符串到包装类: " + wrapperFromIntString);
}
// 基本类型到字符串的转换
public static String intToString(int primitiveInt) {
return Integer.toString(primitiveInt);
}
// 字符串到基本类型的转换
public static int stringToInt(String str) {
return Integer.parseInt(str);
}
// 基本类型到包装类的转换
public static Integer intToWrapperInt(int primitiveInt) {
return Integer.valueOf(primitiveInt);
}
// 包装类到基本类型的转换
public static int wrapperToInt(Integer wrapperInt) {
return wrapperInt.intValue();
}
// 包装类到字符串的转换
public static String wrapperToString(Integer wrapperInt) {
return wrapperInt.toString();
}
// 字符串到包装类的转换
public static Integer stringToWrapperInt(String str) {
return Integer.valueOf(str);
}
}
6.1.3 自动拆箱和自动装箱
在JDK 5之前,基本数据类型和包装类之间的互相转换是需要依赖于包装类中的一些
方法的,不是很方便,而JDK 5之后,Java 提供了自动装箱与自动拆箱机制。
基本类型数据处于需要对象的环境中时,会自动转换为包装类,这就称为自动装箱。而包装类在需要数值的环境中时,会自动转换成基本类型,这称为自动拆箱。说得更直白一些,自动装箱可以把基本数据类型直接赋值给包装类,而自动拆箱可以把包装类直接赋值给基本数据类型。
以Integer 为例:在JDK5以前,Integeri=5的写法是错误的,必须先创建构造方法将基本数据类型转换成包装类。而在JDK 5以后,Java 提供了自动装箱的功能,因此只需
Integer i=5这样的语句就能实现基本数据类型转换成包装类,底层实际上是JVM 调用Integer.valueOf()方法,这就是Java 的自动装箱,而自动拆箱则调用了 intValue()。
下面通过代码清单 6.2演示自动装箱与自动拆箱,如下所示。
public class AutoboxingAndUnboxingExample {
public static void main(String[] args) {
// 自动装箱:基本类型转换为包装类
int primitiveInt = 10;
Integer boxedInt = primitiveInt; // 这里发生了自动装箱
// 自动拆箱:包装类转换为基本类型
int unboxedInt = boxedInt; // 这里发生了自动拆箱
// 输出结果以验证
System.out.println("原始基本类型: " + primitiveInt);
System.out.println("装箱后的Integer对象: " + boxedInt); // 调用的是Integer的toString方法
System.out.println("拆箱后的基本类型: " + unboxedInt);
// 通过方法参数展示自动装箱和拆箱
printInt(boxedInt); // 传递Integer对象,方法内自动拆箱
Integer returnedBoxedInt = getBoxedInt(); // 方法返回基本类型,但赋值给Integer变量时自动装箱
System.out.println("从方法返回的装箱后的Integer对象: " + returnedBoxedInt);
}
// 接收Integer对象作为参数(自动拆箱为int处理)
public static void printInt(Integer intValue) {
// 这里intValue会被自动拆箱为int
System.out.println("在printInt方法中接收到的基本类型值: " + intValue);
}
// 返回一个基本类型int(赋值给Integer变量时自动装箱)
public static int getBoxedInt() {
return 20; // 返回一个基本类型int
}
}
程序(代码清单6.2)运行结果如图6.2所示。

6.2 String类的概述
6.2.1 String类
String 类对象代表不可变的 Unicode 字符序列,内部使用了一个用final 修饰的字符数组存储数据,一旦 String的值确定了,就不能再改变了,每次通过截取、拼接等操作字符串时,都产生一个新的字符串。
Java 为了方便起见,在使用字符串时也可以像基本数据类型一样直接对其进行赋值,
但依然需要了解 String 的构造方法。构造方法比较简单,如代码清单6.3所示。
public class AutoboxingAndUnboxingExample {
public static void main(String[] args) {
String s1 = "abc";
String s2 = new String();
String s3 = new String(s1);
String s4 = new String(new char[] {'a','b','c'});
String s5 = new String(new byte[] {65,66,67});
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
System.out.println(s4);
System.out.println(s5);
// System.out.println(s1);
}
}
程序(代码清单6.3)运行结果如图6.3所示。

6.2.2 String类查找方法
字符串中提供了大量的查找方法,通过这些方法可以很方便地获取字符串的一些
String 类中与查找相关的方法。String类查找方法如代码清单6.4所示。
public class AutoboxingAndUnboxingExample {
public static void main(String[] args) {
String s = "你好,java";
System.out.println("字符串长度为:"+s.length());
System.out.println("字符串索引3处的字符:"+s.charAt(3));
System.out.println("是否以你开头:"+s.startsWith("你"));
System.out.println("字符串中a第一次出现的索引为:"+s.indexOf('a'));
System.out.println("字符串是否以!结尾:"+s.endsWith("!"));
System.out.println("字符串是否包含“java”:"+s.contains("Java"));
}
}
程序(代码清单6.4)运行结果如图6.4所示。

6.2.3 String类转换方法
用户查找字符串的一些信息,为的是根据查询结果对字符串进行一些处理,因此 String
中还定义了一些转换字符串的方法。下面通过代码清单6.5进行演示。
import java.util.Arrays;
public class AutoboxingAndUnboxingExample {
public static void main(String[] args) {
String s = "北京,上海,广州,深圳,杭州,朝鲜";
String[] ss = s.split(",");
System.out.println(Arrays.toString(ss));
char[] cs = s.toCharArray();
System.out.println(Arrays.toString(cs));
byte[] bs = s.getBytes();
System.out.println(Arrays.toString(bs));
String s2=s.replace("北京","bj");
System.out.println(s2);
String us=s2.toUpperCase();
String us1=s2.toLowerCase();
System.out.println(us);
System.out.println(us1);
String s3=s2.substring(2,6);
System.out.println(s3);
}
}
程序(代码清单6.5)运行结果如图6.5所示。

6.3 其他常用类
6. 3.1 Math类
Math 类是Java 中与数学相关的类,提供了大量数学计算相关的方法,如开平方、三角
函数、随机数等。下面通过代码清单6.6演示。
public class AutoboxingAndUnboxingExample {
public static void main(String[] args) {
double num1=10;
double num2=8;
System.out.println(Math.ceil(num1/num2));
System.out.println(Math.floor(num1/num2));
System.out.println(Math.round(num1/num2));
System.out.println(Math.min(num1,num2));
System.out.println(Math.pow(num1,num2));
System.out.println(Math.max(num1,num2));
System.out.println(Math.sqrt(num2));
System.out.println(Math.random());
}
}
程序(代码清单6.6)运行结果如图6.6所示。

6.3.2 Random类
Random 类比Math类的random()方法提供了更多的方式来生成各种伪随机数,可以生成浮点类型的伪随机数,也可以生成整数类型的伪随机数,还可以指定生成随机数的范围。
当创建一个 Random 类之后,就可以使用它的方法获取随机数了。Random 类中的常
用方法如代码清单6.7所示。
import java.util.Random;
public class AutoboxingAndUnboxingExample {
public static void main(String[] args) {
Random rand = new Random();
int a = rand.nextInt(900000)+100000;
System.out.println("您的验证码为"+a);
}
}
程序(代码清单6.7)运行结果如图6.7所示。

总结
本章主要介绍 Java 开发中常见的一些类的使用,包括包装类、字符串、时间日期、工具类等都是在开发中经常用到的类。本章首先介绍了包装类的用处,以及包装类与基本数据类型之间的转换,进而引出自动拆箱、装箱机制;接着介绍了3种字符串:String、StringBuffer、StringBuilder 的使用方式,以及它们之间的区别,并通过一个程序演示了三者之间的性能损耗,读者需要能够根据不同的场景选择不同的字符串类;之后介绍了日期相关类及其用法,包括如何获取日期、格式化日期、对日期进行计算等;最后指出了本章中的一些知识点可融人的思政元素。
本章整体来说难度偏低,所有内容都只是介绍某个类有哪些常用的方法,以及这些方法的使用方式,没涉及原理以及细节,因此学习成本较低,但依然需要我们花时间对这些知识进行巩固。