[关闭]
@artman328 2022-05-11T13:38:28.000000Z 字数 29137 阅读 1554

程序员之路 —— Java:其实它离你并不遥远

Java OOP


程序员之路系列课程之——

HML 和 CSS:网页呈现的艺术

JavaScript:给网页赋予生命

关系数据库:驾驭信息时代的数据

Vue:让网页应用开发极具乐趣

NodeJS:做一个全栈工程师

PHP:平民的 WEB 开发利器

Laravel:以艺术家的态度开发 Web 应用

Java:其实它离你并不遥远

Spring Boot:用 Java 快速开发 Web 应用

绪言

一、本课程的目的

通过学习,让学员掌握 Java 编程语言以及最为流行的编程方法——面向对象的编程,为后续学习使用 Java 框架开发各种应用打下坚实的基础。

二、本课程的对象

有志于软件开发的所有朋友们,同时:

三、本课程的内容

1、本课程首先介绍了 Java 语言基础,然后深入讨论面向对象编程的三大特征在 Java 中的具体体现;
2、我们要学会如何把自己写的代码打包进行分发,也要学会使用别人分享的包;
3、我们要学会使用 Java 开发的集成开发环境,以提高我们的开发效率;
4、我们还要学会用 UML(统一建模语言)来进行面向对象的分析和设计,并用 Java 语言来实现它;
5、我们要学会对自己的代码进行单元测试,并试着用测试驱动的方法编写程序;
6、最后,我们要介绍 Java 开发的流行框架,为学员后续学习用框架开发 Java 企业级应用及移动应用打下基础。

四、本课程的特点

五、如何学习

第一章 什么是面向对象编程

面向对象编程是为抛弃过程式编程的弊端而出现的。

一、过程式编程

过程式语言通常提供大量内建函数(函数:一种对数据完成处理的程序单元),程序使用了大量内建函数和自定义的函数来处理数据,数据被传递给函数,函数返回处理结果。
在过程式编程中,数据和处理数据的程序是分离的,但程序与数据的结构和处理要求高度耦合,程序是针对数据的结构而“定制”的,很难拿去处理不同结构和处理要求的数据。
也就是说,这种类型的编程,程序代码很难得到重用。

bhOuee.md.png

二、面向对象编程

1、类和对象

我们知道,人类在处理任何事务时,都是通过人与人之间或者部门与部门之间互通消息(传递资料)相互协作来完成的。每个人或部门自己保存属于自己的数据,自己处理自己的数据。

bhOWTJ.md.png

面向对象的编程,其实是一种“仿生学”编程。
面向对象编程模拟了以上事务处理过程,它让处理数据的程序自己保存数据,自己处理自己的数据,然后与“别人”协作(传递数据)来完成特定的事务。
在面向对象的世界里,一切都是“活”的,那是一个超自然的世界。比如一张“发票”可以“添加”一项“商品”到自己的“商品项”中,也可以“统计”自己的“商品总额”;一次“会议”可以“指定”自己的“会议地点”等,可以“统计”自己的参会人数等。
在面向对象的编程中,一切都是“对象”(object),而这些对象是分了“类”(class)的。

(1)类(class)
我们知道,人类认识世界,是把各种事物进行了分类的,比如:“公路”、“河流”、“运动会”等。类是指某一类事物,这些事物具有自己的属性。比如:“雇员”就是一类事物,它具有“雇员编号”、“姓名”、“性别”、“出生日期”、“雇用日期”等属性。
类是分层次的,比如以上的“雇员”类,应该隶属于“人”类,而“汽车”类,应该属于“交通工具”类。

bhXSpt.md.png

每一种“类”除了具有自己的属性外,还具有自己的行为,如“雇员”类就具有“上班”、“提交报告”、“告诉别人自己的名字”、“提供自己的银行卡号”等行为。

(2)对象(object)
对象是某类事物中的具体个体。比如“编号:0101,姓名:Dan Foster,性别:男,出生日期:1998-12-23,雇用日期:2019-10-10”的雇员,就是“雇员”类的对象(object),也叫实例(instance)。

bhXVts.md.png

在面向对象的编程中,数据(属性)和操作数据的代码(行为)封装在了一起,并且很容易通过继承来定制自己需要的类(添加更多的属性,添加更多的行为或改写已有的行为),使得代码的重用成为了可能。

bhXrAH.md.png

2、对象合作完成事务过程举例

属性 行为
Group(小组) 名称
组员们
设置和修改自己的名称
把一个组员对象加到自己的组员们中去
把某个组员从自己的组员们中移走
Member(组员) 姓名
性别
出生日期
设置和修改自己的各个属性
DB(数据库) 连接数据库的各种属性 设置和修改自己的各个属性
从数据库中读取对象
把对象存储到数据库

一个“上帝”类(主类)在操纵一切。
1、它先按照 Group 类的规划,“创造”了一个具体的小组对象,并告诉小组对象把自己的“名称”设置为“编程组”;
2、它再按照 Member 类的规划,“创造”了一个具体的组员对象,并告诉它把自己的“姓名”设置成“李超”,“性别”设置成“男”,“出生日期”设置成“1999-01-23”;
3、它把“李超”这个组员对象交给“编程组”对象,让它把“李超”加到自己的“组员们”中;
4、最后,它根据 DB 类的规划,“创造”了一个具体的数据库对象,把它需要的属性传递给它,让它自行设置自己的属性以便连接到数据库服务器,然后把“编程组”对象传递给它,让它把“编程组”对象以及“编程组”对象的组员们里的对象全部保存到数据库中。

bhXT4s.md.png

注意,整个过程中,每个对象都自己完成自己的工作,因为上述“上帝”类都是要求各个对象完成自己的任务,它顶多传递了数据。
事实上,任何对象也可按需要“创造”其它对象供自己使用,不仅限于“上帝”类。但“上帝”类是一切行为的“发起人”而已,就像足球开场时第一个踢球的人。

第二章 Java 语言介绍

Java语言是较为纯粹的面向对象的编程语言,它的源代码需要编译成特定的代码(字节码)后交给 Java 虚拟机(Java Virtual Machine, JVM)来执行。因此,Java 是编译型的语言。

相对编译型语言,是解释型语言。它不需要编译后才执行,而是由一种叫解释器的程序逐句逐句地读取解释给操作系统来执行。

2.1 Java 语言是编译型语言

所谓编译型语言,是指程序员写的计算机程序(叫源程序、源代码)需要编译成另外一种语言后才能被计算机执行。
编译型语言有针对操作系统编译和针对虚拟机编译两大类。

2.2.1 针对操作系统的编译

在计算机发展的早期,计算机程序需要编译成操作系统能够识别和执行的代码才能够被执行,因此在不同的操作系统上编译的程序不会被其它操作系统识别并执行。同时,不同的操作系统提供的底层服务不同,尽管程序功能完全一样,为不同的操作系统所编的程序也不同。
这就造成了同样功能的计算机软件,针对不同的操作系统需要写一套代码,并在自己的操作系统上进行编译。
这些问题是因为操作系统的不同而导致的。
最典型的针对操作系统编译的计算机语言是 C 语言。

bhXvbF.md.png

2.2.2 针对虚拟机的编译

针对虚拟机编译,是指源代码被编译成某种“虚拟的操作系统”支持的格式,并由这个“虚拟的操作系统” 执行。
Java 语言如果针对操作系统进行编译,那么,相同的软件就需要针对不同的操作系统来编写!
难道不能让全世界统一只用一种操作系统吗?你说呢?
因此,Java 团队针对不同的操作系统开发了一套“虚拟的操作系统”,它被称为 Java 虚拟机,让它寄生在这些操作系统中,所有 Java 程序只针对这个“虚拟机”进行编译,如何执行由“虚拟机”与底层的操作系统来决定。这样,所有的 Java 程序编译后,都能在具有 Java 虚拟机的操作系统中运行!这个特性叫跨平台运行

bhjSUJ.md.png

除了需要编译运行的编译型语言外,我们还有一类解释型的语言。只要给不同的操作系统提供解释器,就能实现跨平台运行。

bhjP81.md.png

2.2 Java 语言是静态类型语言

计算机程序中用“变量”来存储数据,一个变量是具有名称的计算机内存中的某个区域。 编程人员只管使用名称来使用这个区域,而不需要管这个区域的具体位置。如变量 a 中装有一个整数 10。
在计算机内部,为了正确处理信息数据,所有数据都具有类型,因为不同的类型运算法则不同。
声明一个变量来装载数据时,需要指明装载的是什么类型的数据,并且以后都只能装这种类型的数据,具有这种要求的语言叫静态类型语言。

动态类型语言的变量可以随时更换装载的数据类型。

bhjmUH.md.png

2.3 JRE 和 JDK

JRE (Java Runtime Evironment),是 Java 运行时环境,它是 Java 虚拟机以及虚拟机运行时需要的程序库构成的,是 Java 程序运行的平台。正是有了不同操作系统下的 JRE,同一个Java 程序才可能在不同的操作系统上运行。
JDK (Java Development Kit) 是用于 Java 开发的工具包。它提供了开发 Java 程序需要的编译工具和一些基础程序库。JDK 本身带有 JRE,因此安装 JDK 后就不需要安装 JRE 了。

动手实践:下载安装 JDK

第三章 编写第一个 Java 程序

3.1 安装编辑器

为了让大家充分理解 Java 程序的组织、编写、编译、打包分发等具体过程,我们暂时不用任何 IDE (集成开发环境,Integrated Developing Evironment),而是采用一款轻量级的程序代码编辑器进行代码编写。
我们将利用 Sublime Text 作为我们目前的代码编辑器。

3.2 编写第一个“上帝”类

“上帝”类我们叫做主类,它里边有一个叫做 main 的函数(在面向对象的编程中,类的函数 function 又叫成员函数,又叫方法 method)。

  1. public class MyApp{
  2. public static void main(String[] args){
  3. System.out.println("这是我的第一个程序");
  4. }
  5. }

在 Java 中,一切都是类。类的声明是:

  1. 可见性修饰符 class 类名 {
  2. ...
  3. }

可见性修饰符包括 public(公开的)、protected(被保护的)、private(私有的)和 default(缺省的,不写任何修饰符)。
关于可见性的讨论,我们会在“类的封装”一章中进行。

函数是完成特定功能的一段包装好的程序,它可以接收传递给它的数据,执行后返回结果。类的成员函数(又叫方法)定义形式如下:

  1. 可见性修饰符 是否静态 返回值类型 函数名([数据类型 变量1, 数据类型 变量2, ...]){
  2. ...
  3. }

函数名后括号中的 数据类型 变量1, 数据类型 变量2, ... 叫做函数的参数列表,每一个变量是一个参数(形式参数)。

主类之所以是主类,是因为它有一个公开的(public)、静态的(static)、不返回任何值(void)的、接收一个字符串数组类型(String[])的数据作为参数的、叫做 main 的函数!而不是由类的名称决定。

  1. public static void main(String[]){
  2. ...
  3. }

这个函数是整个 Java 程序的入口。

在初中数学中,我们学过这样的表达式:


为关于 的函数,其中 为参数, 为函数的算法。
当把 代入时:

也就是说,当 时,函数的值是
和数学中的函数类似,在计算机程序中,函数也是一种“算法”,只不过这种“算法”是用计算机程序来表达。并且,有的计算机程序的函数可能并不会产生一个结果“值”,或对产生的结果不感兴趣,其功能只是为了完成某些操作而已。

在本程序中,System 是一个类,out 是它的一个静态属性,它装着一个打印类的对象,println 是打印类的方法(即成员函数),它把传递给它的字符串打印到屏幕上……听不懂?没关系,目前知道 System.out.println() 是往屏幕上输出字符串就够了。

把以上代码保存到磁盘某个文件夹中,比如:d:\java_work 中,并以 MyApp.java 命名。

注意:Java 的程序文件名与文件里的类名要严格一致!如果一个文件里有多个类,文件名要与标记了 public 的那个类名称严格一致!

3.3 编译

现在到 Windows 的命令窗口,来到 d:\java_work 中。执行以下命令对我们的主类进行编译:

  1. d:\java_work>javac MyApp.java

这时候,会发现当前目录下生成了一个叫做 MyApp.class 的文件,它是我们编译好的字节码程序。

3.4 执行

用以下命令调用虚拟机来执行我们的程序:

  1. d:\java_work>java MyApp

java 就是我们的虚拟机,后面跟上我们的主类的名字,虚拟机就会去执行我们主类的那个 main() 函数里的代码。

第四章 Java 的数据类型

所有信息数据在计算机内部都是二进制数据,为了正确处理信息,计算机程序需要知道它处理的是什么类型的数据。

4.1 关于二进制

二进制
只用两个数字符号 0 和 1 表示数值的体制。
参见:百度百科——二进制

二进制进位规则
“逢二进一” 是二进制的规则。0,1,10,11,100,101,110,111,1000 ...

计算机为什么要用二进制表示数字?
因为可以保证电路两个明确的状态:高电压和低电压。

字节
8位二进制数构成一个字节(byte)。
计算机在处理信息时,数据是被划分为8位二进制数(称为一个字节)为一个基本单元的。8位二进制数,由8个1或0构成,当8位都是0时,为十进制的0,当8位都是1时,为十进制的 255。因此,8位二进制数可有256个组合,相当于: ,以此类推,n 位二进制数可有 个组合,可表示 0~

4.2 Java 的数据类型分类

bhjGqS.md.png

4.3 Java 基本数据类型

数据类型 默认值 值范围 默认字节数 使用举例
boolean false false(假),true(真) 1 位 性别,开关状态...
char '\u0000' '\u0000'~'\uffff'
或:0~65535
2 字节 所有单个字符
byte 0 -128~+127 1 字节 汽车的座位数、气温(摄氏度)
short 0 -32,768~+32,767 2 字节 民航座位数
int 0 -2,147,483,648~+2,147,483,647 4 字节 国土面积(平方公里)
long 0L -9,223,372,036,854,775,808~+9,223,372,036,854,775,807 8 字节 全球人口数,任何天文数字!
float 0.0f ±3.40282347E+38F (6-7有效小数位数) 4 字节 微观宏观较精密数字但不准确
不要用来表示金额
double 0.0d ±1.79769313486231570E+308 (15 有效小数位数) 8 字节 微观宏观精密数字但不准确
不要用来表示金额

4.4 Java 的非基本数据类型

非基本数据类型其实是类(class),所以就具有了处理数据的方法。事实上,从广义上说,任何类都是一种新的“数据类型”。

基本数据类型也用它们对应的非基础数据类型,如:基本数据类型 int 对应着 Integer 非基本数据类型,基本数据类型 float 对应着 Float 非基本数据类型等。

事实上,基本数据类型对应的非基本数据类型是对基本数据类型的“包装”,使得“无生命”的基本数据类型具有了生命,即可对自己的基本数据类型数据进行各种操作。以后我们会详细说到。

Java 平台提供的最常用的非基本数据类型包括“字符串”(String)和“数组”(Array)。

字符串
字符串类型的数据由零到多个单个字符串接而成,用双引号括起来,如:
"I'm happy!"。

数组类型
数组类型是一种集合,里边装着同一种数据类型的多个数据。如:
{"Spring", "Summer", "Autumn", "Winter"}。

第五章 变量、常量与各种运算

5.1 变量与常量

变量常量都是用来存储数据的,它们对应内存区域中的某个位置。
变量中的值可以随时被改变(Java中,数据类型不能变),而常量一旦装上数据就不能再改变。

5.1.1 变量和常量命名规范

合法的如:
_count, firstName, name2 ...
非法的如:
2you, my-name, while ...

5.1.2 变量声明

声明一个变量的语法是:

  1. 数据类型 变量名称;

比如:

  1. float height;

意思是,“我需要一个内存空间来装小数数据,取名叫做 height”。

5.1.3 变量赋值

给变量或常量装上数据叫赋值。
如给以上声明的变量 height 装上数据 180.16:

  1. height = 180.16f;

注意: 变量需要先声明后才能赋值。
当然,我们可以一步做到声明和赋值,如:

  1. float weight = 78.98f;

5.1.3 常量声明与赋值

常量只能做一次赋值(通常会边声明边赋值),然后,在整个程序运行期间再也不能赋值。
语法如下:

  1. final double PI = 3.14159d;

可见,常量声明只是在数据类型前面加了一个关键字“final”(最终的)。
常量名不一定要用大写,但有一种习惯,把常量写成大写,程序员自己就知道它是一个常量。

动手实践 1. 基本数据类型

  1. /**
  2. * CalAreaApp: Calculate Area App.
  3. */
  4. public class CalAreaApp {
  5. /*
  6. 这是 Java 程序的入口 main 函数
  7. 这些内容是注释内容。
  8. */
  9. // 这是单行注释
  10. public static void main(String[] args){
  11. // radius = 1.5;
  12. float radius = 1.5f; //float 的值后面要加f.
  13. final double PI = 3.1415926; //double 的值后面可加 d 或不加
  14. // PI = 3.1415926;
  15. System.out.printf("The area is %.2f\n", radius*radius*PI);
  16. }
  17. }

printf() 用于打印格式化客串,% 号后面的字符串用于控制变量的输出,叫做控制字符,每个控制字符与函数后面的变量一一对应。
%.2f 意思是:小数保留两位的浮点小数。
\n 表示换行符,即输出一个回车换行。

参见“附录一 Java 格式化字符串的转换符”

动手实践 2. 字符串和数组

main(String[] args) 函数接收一个字符串数组到变量 args (数组对象)中。如果我们在执行我们的程序时使用如下命令:
java MyApp I am happy
我们的 args 里的数据就是 {"I", "am", "happy"}。为了得到数组里的数据,我们用“下标”(位置序号,从左至右,从 0 开始)来指定某个数据(叫数组元素)。在 args 中:
args[0]="I", args[1]="am", args[2]="happy"

因为 args 是一个数组对象,它就有了自己的属性。它的一个重要属性是自己包含的元素个数,也叫长度(length)。访问一个对象的属性,方法是:
对象.属性
那么能够得到 args 对象的元素个数的属性就是:
args.length
以下程序在屏幕上输出一句问候语,问候的名字是第一个参数带来的:

  1. public class HelloApp {
  2. public static void main(String[] args) {
  3. String name = "You";
  4. if(args.length>0){
  5. name =args[0];
  6. }
  7. System.out.printf("Hello, %s\n", args[0]);
  8. }
  9. }

5.2 运算

5.2.1 算术运算

运算符 含义 例子
+ 加法运算 x+y
- 减法运算 x-y
* 乘法运算 x*y
/ 除法运算 x/y
% 取模运算(求余运算) x%y
++ 自增1 x++ 或 ++x
相当于 x=x+1
-- 自减1 x-- 或 --x
相当于 x=x-1

5.2.2 关系运算

关系运算的结果是逻辑值:true 或 false。

运算符 含义 例子
< 小于 x
> 大于 x>y
<= 小于等于 x<=y
>= 大于等于 x>=y
== 等于 x==y
!= 不等于 x!=y

5.2.3 逻辑运算

下表中的 a 或 b 可以是逻辑值,也可以是关系运算表达式。

运算符 含义 例子 规则
&& a && b 全真才真
|| a || b 全假才假
! !a 取反

动手实践

  1. public class CalcApp {
  2. public static void main(String[] args){
  3. String firstName = "Tracy";
  4. String lastName = "Walker";
  5. System.out.printf("Hello, my name is %s.\n", firstName+" "+lastName);
  6. int a=10, b=20;
  7. System.out.printf("a=%d, b=%d\n",a,b);
  8. System.out.printf("a+b=%d\n",a+b);
  9. System.out.printf("a-b=%d\n",a-b);
  10. System.out.printf("a*b=%d\n",a*b);
  11. System.out.printf("a/b=%d\n",a/b);
  12. System.out.printf("a%%b=%d\n",a%b);
  13. System.out.printf("a>b: %b\n",a>b);
  14. System.out.printf("a==b: %b\n",a==b);
  15. System.out.printf("a<b: %b\n",a<b);
  16. System.out.printf("a>=b: %b\n",a>=b);
  17. System.out.printf("a<=b: %b\n",a<=b);
  18. System.out.printf("a!=b: %b\n",a!=b);
  19. int x, y;
  20. x = 5;
  21. y = x++; // 相当于:y=x; x=x+1;
  22. System.out.printf("x=5; y=x++; then: x is %d, y is %d\n",x,y);
  23. x = 5;
  24. y = ++x; // 相当于:x=x+1; y=x;
  25. System.out.printf("x=5; y=++x; then: x is %d, y is %d\n",x,y);
  26. }
  27. }

5.3 变量的数据类型转换

5.3.1 扩展与自动转换(隐式转换)

扩展与自动转换在以下情况下是自然发生的:

兼容的数据类型:
同一类数据类型是兼容的。数值型中的 byte、short、int、long、float、double 等是兼容的,它们与 char 不兼容,与 boolean 也不兼容。char 和 booleann 之间也是不兼容的。

byteshortintlongfloatdouble

如:

  1. byte b = 10; // 二进制:00001010
  2. short s = b; // b 的 byte 类型的值 10(1 个字节) 会被转换为短整型的值 10(两个字节) 再赋予变量 s,二进制:00000000 00001010。
  3. int i = s; // s 的短整型的值 10(两个字节) 会被转换为整型的值 10(四个字节)再赋予变量 i,二进制:00000000 00000000 00000000 00001010

5.3.2 手动转换(显式转换)

以下情况下的数据转换需要显式转换:

doublefloatlongintshortbyte

如:

  1. int i = 60000028; // 00000011 10010011 10000111 00011100
  2. char c = (char) i; // 10000111 00011100
  3. byte b = (byte) i; // 00011100

动手实践

  1. public class ConvApp {
  2. public static void main(String[] args){
  3. byte b1 = 10; // 00001010
  4. short s1 = b1; // 00000000 00001010
  5. int i1 = s1; // 00000000 00000000 00000000 00001010
  6. long l1 = i1; // 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00001010
  7. float f1 = l1;
  8. double d1 = f1;
  9. double d2 = 45675657545.19;
  10. float f2 = (float) d2;
  11. long l2 = (long) f2; // 00000000 00001010 10100010 01111011 01000000 00000000
  12. int i2 = (int) l2; // 10100010 01111011 01000000 00000000
  13. short s2 = (short) i2; // 01000000 00000000
  14. byte b2 = (byte) s2; // 00000000
  15. System.out.printf("double: %.2f\n",d2);
  16. System.out.printf("float: %.2f\n",f2);
  17. System.out.printf("long: %d, %s\n",l2,Long.toBinaryString(l2));
  18. System.out.printf("int: %d, %s\n",i2,Integer.toBinaryString(i2));
  19. System.out.printf("short: %d, %s\n",s2,Integer.toBinaryString(s2));
  20. System.out.printf("byte: %d, %s\n",b2,Integer.toBinaryString(b2));
  21. }
  22. }

第六章 Java 基本语句

6.1 表达式、语句和语句块

6.1.1 表达式

表达式是运算式,会得到单一结果。
如:a+bx+y()+z等。
表达式要注意运算符的优先级,比如:a+b*c(a+b)*c是不一样的。

6.1.2 语句

语句是一个执行单元,是组成程序的最小单位。
每个语句都以分号(;)结束。请注意,在所有的编程语言中,各种符号都必须是英文符号。

6.1.3 语句块

语句块是由一对花括号括起来的一条到多条语句。一个语句块是一块“领地”,外面看不到它的内部,但内部可以看见外部。语句块可以嵌套,内层语句块看得见外层语句块,反之则不然。
以语句块结束的语句不需要用分号结束。

6.2 流程控制语句

流程控制语句控制着程序的走向。

6.2.1 if 条件语句

如果(if)符合某个条件,就……,否则(else)就……。
如:

  1. if(a>b){
  2. ...
  3. }

带上“否则”:

  1. if (a>b) {
  2. ...
  3. }
  4. else {
  5. ...
  6. }

也可这样:

  1. if (a==10) {
  2. ...
  3. }
  4. else if (a==20){
  5. ...
  6. }
  7. else if (a==30) {
  8. ...
  9. }
  10. else {
  11. ...
  12. }

动手实践

  1. public class CondApp {
  2. public static void main(String[] args){
  3. String season;
  4. if(args.length>0){
  5. season = args[0];
  6. }
  7. else{
  8. season = "unknown";
  9. }
  10. if(season.equals("unknown")){
  11. System.out.println("You should tell me a season!");
  12. }
  13. if(season.equals("spring")){
  14. System.out.println("It's a mild season. I like "+season);
  15. }
  16. if(season.equals("summer")){
  17. System.out.println("We always go to swim in the "+season);
  18. }
  19. if(season.equals("autumn")){
  20. System.out.println("There are many fruits in the market in the "+season);
  21. }
  22. if(season.equals("winter")){
  23. System.out.println("It's very cold here in the "+season);
  24. }
  25. if(!season.equals("spring") && !season.equals("summer") && !season.equals("autumn") && !season.equals("winter") && !season.equals("unknown")){
  26. System.out.println("I don't know what you are talking about!");
  27. }
  28. }
  29. }

改写:

  1. public class CondApp {
  2. public static void main(String[] args){
  3. String season;
  4. if(args.length>0){
  5. season = args[0];
  6. }
  7. else{
  8. season = "unknown";
  9. }
  10. if(season.equals("unknown")){
  11. System.out.println("You should tell me a season!");
  12. }
  13. else if(season.equals("spring")){
  14. System.out.println("It's a mild season. I like "+season);
  15. }
  16. else if(season.equals("summer")){
  17. System.out.println("We always go to swim in the "+season);
  18. }
  19. else if(season.equals("autumn")){
  20. System.out.println("There are many fruits in the market in the "+season);
  21. }
  22. else if(season.equals("winter")){
  23. System.out.println("It's very cold here in the "+season);
  24. }
  25. else{
  26. System.out.println("I don't know what you are talking about!");
  27. }
  28. }
  29. }

6.2.2 switch 切换语句

switch 语句根据某个变量的取值进行选择执行。

  1. switch(var){
  2. case value1:
  3. ...
  4. [break;]
  5. case value2:
  6. ...
  7. [break;]
  8. case value3:
  9. ...
  10. [break;]
  11. ...
  12. [default:
  13. ...
  14. ]
  15. }

如:下面语句,将根据变量 season 的取值输出不同的信息。

  1. public class SwitchApp {
  2. public static void main(String[] args){
  3. String season = "None";
  4. if(args.length>0){
  5. season = args[0].toLowerCase();
  6. }
  7. switch(season){
  8. case "None":
  9. System.out.println("You should tell me a season!");
  10. break;
  11. case "spring":
  12. System.out.println("It's the most comfortable season!");
  13. break;
  14. case "summer":
  15. System.out.println("Let's go to swim!");
  16. break;
  17. case "autumn":
  18. System.out.println("There are many fruits on the market!");
  19. break;
  20. case "winter":
  21. System.out.println("I never swim in the winter!");
  22. break;
  23. default:
  24. System.out.println("I don't know what to say!");
  25. }
  26. }
  27. }

6.2.3 while 和 do while 语句

while 检测条件是否满足,满足就一直循环,不满足则跳出循环。

  1. while (条件){
  2. 循环体
  3. }

动手实践

  1. public class WhileApp {
  2. public static void main(String[] args){
  3. int count = 10; // try 0
  4. while(count>0){
  5. System.out.printf("%d\n",count);
  6. count --;
  7. }
  8. }
  9. }

do {} while 先做一次循环体,再检测条件是否满足。满足就一直循环,不满足则跳出循环。

  1. do {
  2. 循环体
  3. } while (条件);

动手实践

  1. public class DoWhileApp {
  2. public static void main(String[] args){
  3. int count = 10; // try 0
  4. do {
  5. System.out.printf("%d\n",count);
  6. count --;
  7. } while(count>0);
  8. }
  9. }

6.2.4 for 语句

for 语句设置循环次数的初始值、边界值以及循环一次变动的值。当循环次数达到边界条件时结束循环。

  1. for (int i=0; i<10; i++) {
  2. 循环体
  3. }

以及

  1. for (type var : array)
  2. {
  3. 循环体
  4. }

动手实践

  1. public class ForApp {
  2. public static void main(String[] args){
  3. for(int i=0; i<args.length; i++){
  4. System.out.printf("%s\n",args[i]);
  5. }
  6. }
  7. }

动手实践

  1. public class ForEachApp {
  2. public static void main(String[] args){
  3. for(String arg : args){
  4. System.out.printf("%s\n",arg);
  5. }
  6. }
  7. }

6.2.5 分支语句

1、break
break 打断当前流程,跳出当前语句块。

动手实践

  1. import java.util.Scanner;
  2. public class BreakApp {
  3. public static void main(String[] args){
  4. Scanner input = new Scanner(System.in); // Create a Scanner object
  5. String input_string = "";
  6. while(true){
  7. System.out.print("\nEnter a word: ");
  8. input_string = input.nextLine();
  9. if(input_string.equals("exit")){
  10. System.out.println("Bye!");
  11. break;
  12. }
  13. else{
  14. System.out.println("You entered: " + input_string);
  15. }
  16. }
  17. }
  18. }

2、continue
continue 打断当前流程,返回循环开始处进行下一次循环。
3、return
return 语句结束当前函数,并将结果返回给调用者。

6.3 错误处理

6.3.1 声明抛出错误

定义函数时,声明函数的执行可能发生某种错误,但在函数中不予处理,希望调用者进行处理或继续抛出。

  1. public int getAvg(total,count) throws ArithmeticException {
  2. return total/count;
  3. }

6.3.2 捕获错误

对于可能发生的错误进行捕获。这些错误可能来自自身代码,也可能来自对其它声明抛出错误的函数的调用。

  1. try {
  2. 可能出错的代码
  3. }
  4. catch (错误类型 错误对象) {
  5. 错误处理代码
  6. }
  7. finally{
  8. 必须进行的操作(如关闭资源等)
  9. }

动手实践
从命令接收第一个参数,并试图把它转换成一个整数,然后判断它的奇偶性。

  1. public class CovertApp {
  2. public static void main(String[] args) {
  3. int num = 0;
  4. if(args.length==0){
  5. System.out.println("Usage: java ConvertApp [integer]");
  6. return;
  7. }
  8. try{
  9. num = Integer.parseInt(args[0]);
  10. }
  11. catch(Exception e){
  12. }
  13. if(num%2==0){
  14. }
  15. else{
  16. }
  17. }
  18. }

第七章 封装

封装是面向对象编程语言组织代码并确定代码被访问权限的方式。

7.1 包

为了便于管理代码,Java 以包的形式组织各个类。包具有层次结构,以 a.b.c.d 的形式构成。如果你的程序要向在公共领域内使用,为了保证世界上的包的命名不发生冲突,通常以真实域名以反转的形式来命名。如 gettoweb.net 是我的真实合法的域名,我开发的程序的包将以 net.gettoweb 作为开头来命名,就能保证我的包名在世界上是独一无二的(因为域名的唯一特性)。
包的声明将在类定义之前用 package 来声明。
文件: D:\JavaTut\ShopApp.java

  1. // 没有声明包,就是默认包
  2. import net.gettoweb.shop.model.Shop; // 引入 Shop 类定义
  3. public class ShopApp {
  4. public static void main(String[] args){
  5. Shop shop = new Shop(); // 生成 Shop 类的对象
  6. ...
  7. }
  8. }

文件:D:\JavaLib\net\gettoweb\shop\model\Shop.java

  1. package net.gettoweb.shop.model;
  2. public class Shop {
  3. ...
  4. }

包名指明了类或接口等存在的具体位置。包名的第一部分一定处于被 Java 虚拟机搜索的某个位置中。

  1. D:\JavaTut\>javac --class-path D:\JavaLib;. ShopApp.java
  2. D:\JavaTut\>java -cp d:\JavaLib;. ShopApp

--class-path 或者 -classpath 或者 -cp 用于指定 Java 虚拟机的搜索位置(路径)。

Java 虚拟机的搜索位置:Java 虚拟机在调入某个类或接口时,需要在文件系统中找到这个类或接口的代码,对于 net.gettoweb.shop.model.Shop这个类,虽然知道 Shop.class 一定处于 net 文件夹中的 gettoweb 的文件夹中的 shop 文件夹中的model文件夹中,但是,net` 文件夹在文件系统的什么地方?这个地方就一定要加入到 Java 虚拟机搜索的位置当中。
因为 Java 虚拟机可以在压缩包中读取类,而压缩包内部可能也包含了整个目录结构,我们也可把压缩包指定为搜索位置。

动手实践
1、编写 net.gettoweb.shop.model.Shop 类,属性包含名称、地址,以及针对属性进行读写的方法及构造函数。
编写一个主类(默认包),ShopApp,在这个类中实例化一家叫做“时尚服装”的商店,地址在“昆明市中华路明德商贸城A-123”。然后显示这家商店的所有信息到屏幕上。

  1. //D:\JavaProj\net\gettoweb\shop\model\Shop.java
  2. package net.gettoweb.shop.model;
  3. public class Shop {
  4. public String name;
  5. public String address;
  6. public Shop(String name, String address){
  7. this.name = name;
  8. this.address = address;
  9. }
  10. public String toString(){
  11. return this.name + " : " + this.address;
  12. }
  13. }
  1. //D:\JavaProj\ShopApp.java
  2. import net.gettoweb.shop.model.*;
  3. public class ShopApp {
  4. public static void main(String[] args){
  5. Shop shop = new Shop("Fashion Shop","A-123 Yuantong Street, Kunming city, YN, China");
  6. System.out.println(shop.toString());
  7. }
  8. }
  1. D:\JavaProj> javac ShopApp.java
  2. D:\JavaProj> java ShopApp
  3. Fashion Shop : A-123 Yuantong Street, Kunming city, YN, China
  4. D:\JavaProj>_

2、将以上 net.gettoweb.shop.model.Shop 类打包到 Shop.jar 中,并利用这个 jar 包再次运行 ShopApp。

  1. D:\JavaProj> jar cvf shop.jar net
  2. D:\JavaProj> java -cl .;.\shop.jar ShopApp
  3. Fashion Shop : A-123 Yuantong Street, Kunming city, YN, China

7.2 类

类是面向对象编程语言的基本单元。除了用包对类进行组织管理以外,类本身也有针对可见性的封装。
定义一个类时,可在最前面加入访问修饰符,以确定其可见性。

  1. [访问修饰 ]

动手实践
3. 将以上 Shop 类定义的 public 去掉,重新编译 ShopApp 类,观察出现的错误。

7.3 类成员

类成员是指类的属性(成员变量)和行为(方法)。

  1. // 属性
  2. [访问修饰符] 数据类型 变量名称;
  3. // 行为
  4. [访问修饰符] 返回值类型 方法名称(参数列表){};

动手实践
4. 将以上 Shop 类的全部属性改为私有(private),并编写公开的对这些属性进行存取的方法,然后重新编译 ShopApp 类并运行。

  1. //D:\JavaProj\net\gettoweb\shop\model\Shop.java
  2. package net.gettoweb.shop.model;
  3. public class Shop {
  4. private String name;
  5. private String address;
  6. public Shop(String name, String address){
  7. this.setName(name);
  8. this.setAddress(address);
  9. }
  10. public void setName(String name){
  11. this.name = name;
  12. }
  13. public String getName(){
  14. return this.name;
  15. }
  16. public void setAddress(String address){
  17. this.address = address;
  18. }
  19. public String getAddress(){
  20. return this.address;
  21. }
  22. public String toString(){
  23. return this.getName() + " : " + this.getAddress();
  24. }
  25. }

第八章 继承

8.1 类的继承

类的继承是面向对象编程的三大特征之一,其目的是代码的重用。

8.1.1 继承非抽象类(具体类)

一个类可以继承另一个类而成为那个类的子类,获得其原有属性和方法,再增加自己特有的属性和方法,被继承的类就叫父类。

用父类申明的变量可以用来装载子类的对象,在这种情况下,只能用它引用父类具有的方法和属性。

动手实践
5. 编写一个"net.gettoweb.school.Person(个人)"类(含“姓名”、“性别”、“出生日期”等基本属性),在同一个包中再编写两个类“Teacher(教师)”和“Student(学生)”,各增加“教师编号(teacherNo)”和“学生编号(studentNo)”两个属性。

  1. // D:\JavaLib\net\gettoweb\school\Person.java
  2. package net.gettoweb.school;
  3. import java.time.LocalDate;
  4. public class Person { // extends Object, 隐式继承公共顶级类 java.lang.Object
  5. private String name;
  6. private String gender;
  7. private LocalDate birthDate;
  8. public Person(String name, String gender, String birthDate){
  9. this.setName(name);
  10. this.setGender(gender);
  11. this.setBirthDate(birthDate);
  12. }
  13. public void setName(String name){
  14. this.name = name;
  15. }
  16. public String getName(){
  17. return this.name;
  18. }
  19. public void setGender(String gender){
  20. this.gender = gender;
  21. }
  22. public String getGender(){
  23. return this.gender;
  24. }
  25. public void setBirthDate(String birthDate){
  26. this.birthDate = LocalDate.parse(birthDate);
  27. }
  28. public LocalDate getBirthDate(){
  29. return this.birthDate;
  30. }
  31. @Override // 声明要重写父类的方法 toString
  32. public String toString(){
  33. return this.getName() + ", " + this.getGender() + ", " + this.getBirthDate();
  34. }
  35. }
  1. // D:\JavaLib\net\gettoweb\school\Teacher.java
  2. package net.gettoweb.school;
  3. public class Teacher extends Person {
  4. private String teacherNo;
  5. public Teacher(String teacherNo, String name, String gender, String birthDate){
  6. super(name, gender, birthDate); // 调用父类的构造函数
  7. this.setTeacherNo(teacherNo);
  8. }
  9. public void setTeacherNo(String teacherNo){
  10. this.teacherNo = teacherNo;
  11. }
  12. public String getTeacherNo(){
  13. return this.teacherNo;
  14. }
  15. @Override // 声明要重写父类的方法 toString
  16. public String toString(){
  17. return "Teacher: " + this.getTeacherNo() + ", " +
  18. this.getName() + ", " + this.getGender() +
  19. ", " + this.getBirthDate();
  20. }
  21. }
  1. // D:\JavaLib\net\gettoweb\school\Student.java
  2. package net.gettoweb.school;
  3. public class Student extends Person {
  4. private String studentNo;
  5. public Student(String studentNo, String name, String gender, String birthDate){
  6. super(name, gender, birthDate); // 调用父类的构造函数
  7. this.setStudentNo(studentNo);
  8. }
  9. public void setStudentNo(String studentNo){
  10. this.studentNo = studentNo;
  11. }
  12. public String getStudentNo(){
  13. return this.studentNo;
  14. }
  15. @Override // 声明要重写父类的方法 toString
  16. public String toString(){
  17. return "Student: " + this.getStudentNo() + ", " +
  18. this.getName() + ", " + this.getGender() +
  19. ", " + this.getBirthDate();
  20. }
  21. }
  1. 编写一个 SchoolApp 主类,各生成一名教师和学生对象,输出他们的基本信息。
  1. import net.gettoweb.school.*;
  2. public class SchoolApp {
  3. public static void main(String[] args){
  4. int a = 10;
  5. Teacher teacher = new Teacher("T0001","Billy Wyne","Male","1979-12-20");
  6. Student student = new Student("S201812001","Tina Green","Female","1998-05-06");
  7. System.out.println(student); // 自动调用 Student 的 toString() 方法
  8. System.out.println(teacher); // 自动调用 Teacher 的 toString() 方法
  9. }
  10. }

8.1.2 继承抽象类

抽象类是一种特别的类,它的一些方法尚无法实现。这些无法实现的方法叫抽象方法,具有抽象方法的类就是抽象类,它不能够被实例化(生成对象)。
如果继承了抽象类的子类实现了父类的全部抽象方法,则可以被实例化,否则仍然要申明为抽象类。

动手实践

  1. public class DrawApp {
  2. public static void main(String[] args){
  3. Shape shape1 = new Circle("Circle",20.0f);
  4. Shape shape2 = new Square("Square",100.00f);
  5. System.out.printf("Area: %.2f\n",shape1.calcArea());
  6. shape1.draw();
  7. System.out.printf("Area: %.2f\n",shape2.calcArea());
  8. shape2.draw();
  9. }
  10. }
  1. public abstract class Shape {
  2. private String name;
  3. public Shape(String name){
  4. this.setName(name);
  5. }
  6. public void setName(String name){
  7. this.name = name;
  8. }
  9. public String getName(){
  10. return this.name;
  11. }
  12. public abstract float calcArea();
  13. public abstract void draw();
  14. }
  1. public class Circle extends Shape {
  2. private float radius;
  3. public Circle(String name, float radius){
  4. super(name);
  5. this.setRadius(radius);
  6. }
  7. public void setRadius(float radius){
  8. this.radius = radius;
  9. }
  10. public float getRadius(){
  11. return this.radius;
  12. }
  13. public float calcArea(){
  14. return this.radius * this.radius * 3.14f;
  15. }
  16. public void draw(){
  17. System.out.println("Circle is drawn.");
  18. }
  19. }
  1. public class Square extends Shape {
  2. private float sideLength;
  3. public Square(String name, float sideLength){
  4. super(name);
  5. this.setSideLength(sideLength);
  6. }
  7. public void setSideLength(float sideLength){
  8. this.sideLength = sideLength;
  9. }
  10. public float getSideLength(){
  11. return this.sideLength;
  12. }
  13. public float calcArea(){
  14. return this.sideLength * this.sideLength;
  15. }
  16. public void draw(){
  17. System.out.println("Square is drawn.");
  18. }
  19. }

8.2 接口

接口是一种特殊的“类”,它用于声明一些方法而不实现,重要的是,它可以继承多个接口丰富自己的“方法库”。接口不能够实例化,只能有其它类来“实现”它。用某个接口申明的变量,可以用来装载实现了该接口的类的对象,但只能使用该接口声明的方法。

动手实践

  1. public class DragonApp {
  2. public static void main(String[] args){
  3. Dragon dragon = new Dragon();
  4. dragon.run();
  5. dragon.fly();
  6. ICanFly flyer = new Dragon();
  7. flyer.fly();
  8. // flyer.run() not supported
  9. ICanRun runner = new Dragon();
  10. runner.run();
  11. // runner.fly() not supported
  12. }
  13. }
  1. public interface ICanFly {
  2. public void fly();
  3. }
  1. public interface ICanRun {
  2. public void run();
  3. }
  1. public class Dragon implements ICanFly, ICanRun{
  2. public void fly(){
  3. System.out.println("Flying...");
  4. }
  5. public void run(){
  6. System.out.println("Running...");
  7. }
  8. }

第九章 多态

多态是面向对象编程的三大特征之一,其目的是代码的解耦合。

9.1 多态的含义

“同一种”对象的同一个方法,行为表现不相同。例如,“交通工具”都有“移动 ”的行为,但“汽车”和“飞机”的“移动”行为并不相同。
这里的“同一种”,是指:

9.2 多态的优点

在某个类中用祖先类或接口声明变量,根据需要装载不同的类的对象而不需要更改这个类的原代码,实现类与类之间的松耦合。

动手实践
编写一个应用,这个应用会调用一个输出类输出信息到不同的目的地。有两个输出类可用,一个类会输出信息到屏幕,而另一个却会将信息输出到文件。
1、非多态实现
用法: java OutputApp "The quick brown fox jumps over the lazy dog."

  1. import net.gettoweb.io.*;
  2. public class OutputApp {
  3. public static void main(String[] args){
  4. String msg = args.length>0? : "Default message.";
  5. ScreenDev outputDev = new ScreenDev();
  6. outputDev.output(msg);
  7. }
  8. }

第6行生成了一个 ScreenDev 对象 screenDev;
第7行用 screenDev 对象的 output 方法将命令行的信息输出到屏幕。
如果需要将信息输出到文件,需要将第6行改成 FileDev outputDev = new FileDev();

  1. package net.gettoweb.io;
  2. public class ScreenDev{
  3. public void output(String msg){
  4. System.out.println("This message has been output to the screen: "+msg);
  5. };
  6. }
  1. package net.gettoweb.io;
  2. public class FileDev implements OutputDev {
  3. public void output(String msg){
  4. System.out.println("This message has been output to a file: "+msg);
  5. };
  6. }

2、多态实现
用法:java OutputApp [screen|file] "The quick brown fox jumps over the lazy dog."

  1. import net.gettoweb.io.*;
  2. public class OutputApp {
  3. public static void main(String[] args){
  4. String devName = args.length>0? args[0].toLowerCase() : '';
  5. OutputDev outputDev;
  6. switch(devName){
  7. case "screen":
  8. outputDev = new ScreenDev();
  9. break;
  10. case "file":
  11. outputDev = new FileDev();
  12. break;
  13. default:
  14. outputDev = new ScreenDev();
  15. }
  16. String msg = args.length>1? args[1]: "Default message.";
  17. outputDev.output(msg);
  18. }
  19. }

第6行用接口 OutputDev 声明了一个变量 outputDev,此变量可装载所有实现了 OutputDev 接口的类的对象,不同的对象针对相同的方法可有不同的实现(多态)。
需要更改输出方向,命令行第一个参数 [screen|file] 可分别将信息输出到屏幕或文件,不需要更改程序。

  1. package net.gettoweb.io;
  2. public interface OutputDev {
  3. public void output(String msg);
  4. }
  1. package net.gettoweb.io;
  2. public class ScreenDev implements OutputDev {
  3. public void output(String msg){
  4. System.out.println("This message has been output to the screen: "+msg);
  5. };
  6. }
  1. package net.gettoweb.io;
  2. public class FileDev implements OutputDev {
  3. public void output(String msg){
  4. System.out.println("This message has been output to a file: "+msg);
  5. };
  6. }

第十章 面向对象的分析与设计

10.1 面向对象的分析

10.1.1 什么是面向对象分析(OOA)?

面向对象分析(OOA)是发现过程,开发团队可在此过程中了解和建模系统需求。在OOA中,需求被组织为对象。它集成了所有过程和数据。但是在其他或传统的结构分析中,过程和数据都被独立/分开地考虑。他们将流程图/结构图用于过程,将ER图用于数据。

但是在OOA中,使用了一些高级模型。OOA中使用的常见模型是:用例,对象模型。用例描述了系统必须实现的标准域功能的图片或概述。对象模型描述了主要对象的名称,类关系,操作和属性。还可以创建用户界面原型以更好地理解。

面向对象分析(OOA)首先查看问题域(需要分析才能解决问题的专业知识或应用程序领域)。其目的是为存在于被分析区域中的信息提供概念模型。为了进行分析,有多种来源。它可以是正式文件,书面要求声明,与利益相关者/其他有关方面的访谈,其他方法等。面向对象分析的最终结果将以概念模型的形式出现,该模型描述了系统在功能上需要做些什么。

传统的结构化分析
该结构分析 /结构化设计(SASD)方法是软件开发的传统方法。它基于瀑布模型。以下是SASD系统的开发阶段:
- 可行性研究
- 需求分析与规范
- 系统设计
- 实作
- 实施后审查

10.1.2 OOA 的功能以下是OOA的核心活动:

10.1.3 OOA 的优点

OOA提供更好的性能。
以下是OOA的一些共同优点:

下面给出了结构化分析和面向对象的分析之间的一些区别:

10.2 面向对象的设计

在分析阶段之后,使用面向对象设计(OOD)将概念模型进一步开发为面向对象模型。在OOD中,将分析模型中与技术无关的概念映射到实现类上,确定约束并设计接口,从而形成解决方案领域的模型。简而言之,构建了详细的说明,指定如何在具体技术上构建系统

面向对象设计的阶段可以标识为

10.2.1 系统设计

面向对象的系统设计涉及定义系统的上下文,然后设计系统的体系结构。

上下文
系统的上下文具有静态和动态部分。使用整个系统的简单框图设计系统的静态上下文,该框图被扩展为子系统的层次结构。子系统模型由UML包表示。动态上下文描述了系统如何与其环境交互。它使用用例图建模。
系统架构
系统架构是根据系统上下文根据架构设计和领域知识设计的。通常,将系统划分为几层,然后分解每一层以形成子系统。

10.2.2 面向对象的分解(详细设计)

分解意味着按照分而治之的原则,将一个大型的复杂系统划分为具有较小复杂性的较小组件的层次结构。系统的每个主要组成部分都称为子系统。面向对象的分解可识别系统中的各个自治对象以及这些对象之间的通信。

分解的优点是

10.3 统一建模语言 UML

UML是一种由一组集成图组成的标准化建模语言,旨在帮助系统和软件开发人员指定,可视化,构建和记录软件系统的构件,以及进行业务建模和其他非软件系统。UML代表了一系列最佳工程实践,这些实践已被证明在大型和复杂系统的建模中取得了成功。UML是开发面向对象软件和软件开发过程的非常重要的部分。UML主要使用图形符号来表达软件项目的设计。使用UML可以帮助项目团队交流,探索潜在的设计并验证软件的体系结构设计。
UML图分两大类,静态图和动态图。

10.3.1 静态图

静态图在不同的抽象和实现级别上显示了系统的静态结构及其各个部分,以及它们之间的相互关系。静态图中的元素表示系统的有意义的概念,并且可能包括抽象,现实世界和实现概念,静态图有七种类型,如下所示:

10.3.2 动态图

动态图显示了系统中对象的动态行为,可以描述为系统随时间的一系列变化,动态图有七种类型,如下所示:

下图为一张类图(结合包图)的样例:
bhjhxx.md.png

下图为一张顺序图的样例:
bhjLid.md.png

第十一章 编写并打包一个类库

第十二章 使用别人的类库

第十三章 使用 IDE 编写 Java 应用

第十四章 Java 的单元测试

第十五章 Java 流行框架介绍

附录

附录一 Java 格式化字符串的转换符

说明符 适用于 输出
%a 浮点数 (除了BigDecimal) 浮点数的十六进制输出
%b 任何类型 如果为非空则为“true”,为空则为“false”
%c 字符 Unicode字符
%d 整数 (包括byte, short, int, long, bigint) 十进制整数
%e 浮点数 科学计数的十进制数
%f 浮点数 十进制数
%g 浮点数 十进制数,根据值和精度可能以科学计数法显示
%h 任何类型 通过hashCode()方法输出的16进制数
%n 平台相关的换行符
%o 整数(包括byte, short, int, long, bigint) 八进制数
%s 任何类型 字符串
%t 日期/时间 (包含long, Calendar, Date 和TemporalAccessor) %t是日期/时间转换的前缀。后面还需要跟其他的标识,请参考下面的日期/时间转换。
%x 整数(包含byte, short, int, long, bigint) 十六进制字符串

日期和时间格式
注意:使用 “%T” 替换下面的 “%t” 可以将输出结果变成大写形式。

标识 注释
%tA 星期几的全名,例如 “Sunday“, “Monday“。
%ta 星期几的缩写,例如 “Sun“, “Mon“。
%tB 月份的全名,例如 “January“, “February“。
%tb 月份的缩写,例如 “Jan“, “Feb“。
%tC 年的世纪部分的格式为两位数,从 “00“到“99”。
%tc 日期和时间的格式为 “%ta %tb %td %tT %tZ %tY” 如 “Fri Feb 17 07:45:42 PST 2017“。
%tD 格式为 “%tm/%td/%ty“ 的日期。
%td 两位的日期格式,从 “01”到 “31“。
%te 没有前导0的日期,从 “1” 到 “31”。
%tF 使用 “%tY-%tm-%td“ 格式的 ISO 8601 日期。
%tH 24小时制的小时,从 “00” 到 “23“。
%th 同 %tb。
%tI 12小时制的小时,从 “01” 到 “12“。
%tj 带前导0的年中的日期,从 “001” 到“366“。
%tk 没有前导0的24小时制,从 “0” 到 “23“。
%tl 没有前导0的12小时制,从 “1” 到“12“。
%tM 带前导0的分钟,从 “00” 到“59“。
%tm 带前导0的月份,从 “01” 到 “12“。
%tN 带前导0的9位纳秒数,从 “000000000” to “999999999”.
%tp 和区域相关的 “am” or “pm” 标记。
%tQ 1970年1月1日00:00:00 UTC 以来的毫秒。
%tR 24小时制的时间,如:“%tH:%tM“。
%tr 12小时制的时间,如:“%tI:%tM:%tS %Tp“。
%tS 2位数字格式的秒,从 “00” 到 “60”。 “60” 需要支持闰秒。
%ts 1970年1月1日00:00:00 UTC以后的秒数。
%tT 24小时制的时分秒,如: “%tH:%tM:%tS“。
%tY 4位的年份格式,从 “0000” 到 “9999“。
%ty 2位的年份格式,从 “00” 到 “99“。
%tZ 时区缩写,如:“UTC“, “PST“。
%tz 与GMT的时区偏移量,如 -0800。
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注