第3章 Java的基本程序设计结构
3.1 一个简单的Java应用程序
/**
* This is the first sample program in Core Java Chapter 3
*
* @author Gary Cornell
* @version 1.01 1997-03-22
*/
public class FirstSample {
public static void main(String[] args) {
System.out.println("We will not use 'Hello, World!'");
}
}
逐行查看此段源代码:
-
public
:访问修饰符,控制程序其他部分对这段代码的访问级别。 -
class
:Java 程序中的全部内容都包含在类中(这里,类作为一个加载程序逻辑的容器,程序逻辑定义了应用程序的行为)。 -
FirstSample
:类名(源代码文件名必须与公共类的名字相同,并以. java 作为拓展名)。 -
public static void main(String[] args) {...}
:每个Java应用程序都必须有一个 main 方法。
🗒️注释:根据 Java 语言规范, main 方法必须声明为 public。
public class ClassName
{
public static void main(String[] args)
{
program statements
}
}
System.out.println("We will not use 'Hello, World!'");
:将一个文本行输出到控制台上。
🗒️注释:
System.out.print——输出内容不换行
System.out.println——输出内容换行
3.2 注释
3种注释方法:
-
//xxx
-
/*xxx*/
-
自动生成文档
❗警告:在 Java 中,/**/不能嵌套(代码本身可能就包含/)*
3.3 数据类型
3.3.1 整型
类型 | 存储需求 | 取值范围 |
---|---|---|
int | 4 字节 | -2147483648 ~ 2147483647 |
short | 2 字节 | -32768 ~ 32767 |
long | 8 字节 | -9223372036854775808 ~ 9223372036854775807 |
byte | 1 字节 | -128 ~ 127 |
说明:
-
int
类型最常用; -
long
类型:大数据; -
byte
和short
类型:特定的应用场合,底层文件处理或需要控制占用存储空间量的大数组。
使用:
-
长整型数值有一个后缀
L
或l
; -
十六进制数值有一个前缀
0x
或0X
; -
八进制数值有一个前缀
0
(不建议使用,容易混淆); -
从 Java7 开始,加上前缀
0b
或0B
就可以写二进制数;为数值加下划线。
©️ C++ 注释:
在 C/C++ 中,int 和 long 等类型大小与目标平台有关
16位处理器(8086中),整型数值占2字节
32位处理器(Pentinum或SPARC),整型数值占4字节
32位处理器,long 占4字节
64位处理器,long 占8字节
......
给跨平台带来了难度。
但是在 Java 中所有数值类型所占据的字节数量与平台无关
Java 没有任何无符号形式的 int
、 long
、 short
或 byte
3.3.2 浮点类型
类型 | 存储需求 | 取值范围 |
---|---|---|
float | 4 字节 | 大约(有效位数为位) |
double | 8 字节 | 大约(有效位数为位) |
使用:
-
float
后缀F
或f
-
double
默认后缀D
或d
🗒️注释:
- 使用十六进制表示浮点数;。
- 表示为;
- 十六进制表示法:
- 表示指数;
- 尾数采用十六进制,指数采用十进制;
- 基数是而不是。
所有的浮点数都遵循规范,下面用于表示溢出和出错情况的三个特殊的浮点数值。
- 正无穷大
- 负无穷大
- (不是一个数字)
🗒️注释:
- 常量:
-
Double/Float.POSITIVE_INFINITY
-
Double/Float.NEGATIVE_INFINITY
-
Double/Float.NaN
-
在实际中很少遇到。
特别说明的是,检测一个特定值是否等于Double/Float.NaN
,注意
if(x == Double.NaN) //if never true
if(Double.isNaN(x)) //check whether x is "not a number"
❗警告:浮点数不适用于无法接受舍入误差的金融计算中
原因:浮点数值采用二进制系统表示,在二进制系统中无法精确表示分数。
如果不允许有任何舍入误差,应使用 BigDecimal
类
3.3.3 char类型
-
有的 Unicode 字符可以用一个 char 值表示,另外一些 Unicode 字符需要两个 char 值;
-
char 类型的字面量值要单引号括起来;
-
char 类型的值可以表示为十六进制值,其范围从\u0000 到 \uffff;
-
除了转义字符 \u 之外,还有一些用于表示特殊字符的转义序列;
转义序列 名称 Unicode \b 退格 \u0008 \t 制表 \u0009 \n 换行 \u000a \r 回车 \u000d \” 双引号 \u0022 \’ 单引号 \u0027 \ 反斜杠 \u005e -
转义序列 \u 还可以出现在加引号的字符常量或字符串之外。
❗警告:Unicode转义序列会在解析代码之前得到处理。
举例1
"\u0022+\u0022”
⇒ “”+“”
\u0022
=“
,\u0022
=”
举例2
// \u000a is a newline
:\u000a
替换为换行符。
举例3
// Look inside c:\users :\users 为非法转义(并未跟着4个十六进制数)。
3.3.4 Unicode和char类型
Unicode 编码机制
在 Unicode 出现之前,还有:
- 美国的 ASCII
- 西欧语言的 ISO 8859-1
- 俄罗斯的 KOI-8
- 中国的 GB 18030, BIG-5
- ......
会产生两个问题:
- 对于任意给定的代码值,在不同的编码方案下有可能对应不同的字母。
- 采用大字符集的语言其编码长度有可能不同(有的常用字符采用单字节编码,而另一些字符需要两个或更多个字节)。
20世纪80年代,人们认为两个字节的代码宽度足以对世界各种语言的所有字符进行编码,并有足够的空间留给未来拓展。
在1991年发布了 Unicode1.0 ,当时仅仅占用65536一半不到,设计 Java 中采用了16位的 Unicode 字符集。
一段时间之后,Unicode 字符超过了65536个,16位的 char 无法满足。
Q:如何解决用16位 char 拓展 Unicode 字符不足的问题?
A:
从 Java SE 5.0 开始,
码点(code point):一个编码表中某个字符对应的代码值。在 Unicode 标准中采用十六进制书写,并加上前缀 U+。
分为个代码级别:
- 第 个代码级别:基本的多语言级别(basic multilingual plane),码点
U+0000
到U+FFFF
,经典的 Unicode 代码。 - 第 到 个代码级别:码点
U+10000
到U+10FFFF
,辅助 Unicode 代码
编码规则( UTF-16 ):
-
: 每个字符用 位表示(代码单元(code unit))
-
:每个字符用 位表示,利用基本多语言级别中空闲的 字节(替代区域(surrogate area))
-
U+D800 ~ U+DBFF
用于第一个代码单元 -
U+DC00 ~ U+DFFF
用于第二个代码单元
区别一个代码单元是一个字符的编码 or 一个辅助字符的第一或第二部分
详解Unicode、UTF-8、UTF-16和UTF-32
统一码
Unicode:Unicode(统一码、万国码、单一码)是一种在计算机上使用的字符编码。它为每种语言中的每个字符设定了统一并且唯一的二进制编码,以满足跨语言、跨平台进行文本转换、处理的要求。
历史
- 1990年开始研发。
- 1994年正式公布。随着计算机工作能力的增强,Unicode也在面世以来的十多年里得到普及。
- Unicode是基于通用字符集(Universal Character Set)的标准来发展,并且同时也以书本的形式(The Unicode Standard,目前第五版由Addison-Wesley Professional出版,ISBN-10: 0321480910)对外发表。
- 2005年3月31日推出的Unicode 4.1.0。
- 2021年9月14日推出的14.0版本。
编码
Unicode用数字0-0x10FFFF映射字符(最多可以容纳1114112个字符)。
码位:分配给字符的数字
UTF-8、UTF-16、UTF-32:将数字转换为程序数据的编码方案。
Unicode字符集(UCS(Unicode Character Set))。
UTF-8
- 单个字节的字符,
0xxxxxxx
(与ASCII码完全相同)。 - N个字节的字符,
1...10x...x 10x...x
。- 第一个字节:1~N为1,N+1为0:
1...10x...x
。 - 剩下N-1个字节:
10x...x
。
- 第一个字节:1~N为1,N+1为0:
举例:
“汉”
编码过程:
Unicode码点0x6c49
对应 二进制0110 1100 0100 1001
Unicode十六进制码点范围:0x6c49
0000 0800 - 0000 FFFF
对应的UTF-8二进制:1110xxxx 10xxxxxx 10xxxxxx
将二进制0110 1100 0100 1001
依次填入“x”
11100110 10110001 10001001
⇒ 十六进制0xE6 0xB7 0x89
解码过程:
- 字节第一位为0,该字节对应一个字符
- 字节第一位为1,多少个1对应该字符占用多少个字符
UFT-16
Unicode不是将所有字符放入一个集合——一次性定义,而是分区定义。
Unicode一共划分有17个平面(),每个平面可以存放65536个字符()
整个Unicode字符集大小是
BMP:基本平面。
-
码点范围
0~$2^{16}$-1
:个字符,2个字节存储- 十六进制表示
U+0000~U+FFFF
- 十六进制表示
-
最常见字符所在
SMP:辅助平面。
-
码点范围~+-1`:个字符,4个字节存储
- 十六进制表示
U+010000~U+10FFFF
- 十六进制表示
UFT-16介于UTF-32与UTF-8之间,结合了定长和变长的两种编码方式
- 基本平面的字符占用2个字节,对应码点范围
U+0000~U+FFFF
- 辅助平面的字符占用4个字节,对应码点范围
U+010000~U+10FFFF
Q:遇到两个字节,我们是将这两个字节作为一个字符还是与后面两个字节作为一个字符?
在基本平面内,U+D800~U+DFFF
为一个空段,不对应任意一个字符
在辅助平面,对应字符有个,需要20位二进制位
UFT-16将20个进制分为两半
前 10 位映射在U+D800~U+DBFF
————高位H
后 10 位映射在U+DC00~U+DFFF
————低位L
举例:
“?”
编码过程:
Unicode码点U+20BB7
对应 :二进制0010 0000 1011 1011 0111
Unicode十六进制码点范围:U+20BB7
U+010000~U+10FFFF
超出部分:
0x20BB7
- 0x10000
=0010 0000 1011 1011 0111
- 0001 0000 0000 0000 0000
=0001 0000 1011 1011 0111
前10位:0001 0000 10
,映射到U+D800~U+DBFF
,得到1101 1000 0100 0010
U+D800
:1101 1000 0000 0000
U+DBFF
:1101 1011 1111 1111
⇒0xD842
后10位:11 1011 0111
,映射到U+DC00~U+DFFF
,得到1101 1111 1011 0111
U+DC00
:1101 1100 0000 0000
U+DFFF
:1101 1111 1111 1111
⇒0xDFB7
⇒ 0xD842 0xDFB7
解码过程:
当遇到两个字节,
不在U+D800~U+DBFF
中,将这两个字节对应的码点读取为Unicode字符
在U++D800~U+DBFF
中,将这两个字节和后面两个字节后10位合并的码点读取为Unicode字符
举例
⑪:http://math.ucr.edu/ ,码点U+1D546
Unicode码点U+1D546
对应 :二进制0001 1101 0101 0100 0110
码点范围:U+1D546
U+010000~U+10FFFF
超出部分:
U+1D546
- 0x10000
=0001 1101 0101 0100 0110
- 0001 0000 0000 0000 0000
=0000 1101 0101 0100 0110
前10位:0000 1101 01
,映射到U+D800~U+DBFF
,得到1101 1000 0011 0101
⇒0xD835
U+D800
:1101 1000 0000 0000
U+DBFF
:1101 1011 1111 1111
后10位:01 0100 0110
,映射到U+DC00~U+DFFF
,得到1101 1101 0100 0110
U+DC00
:1101 1100 0000 0000
U+DFFF
:1101 1111 1111 1111
⇒0xDD46
⇒ 0xD835 0xDD46
在 Java 中,char 类型只描述了 UTF-16 编码中的一个代码单元,我们不建议使用 char 类型,除非确实需要处理 UTF-16 代码单元,最好将字符串作为抽象数据类型处理。
3.3.5 boolean类型
boolean
(布尔)类型只有两个值:false 和 true 。
©️ C++ 注释:在 C++ 中,数值甚至指针可以代替 boolean 值。值 0 相当于布尔值 false ,非 0 值相当于布尔值 true 。在 Java 中不能用数值代替布尔值。
3.4 变量
在 Java 中,每个变量都有一个类型(type)
double salary;
int vacationDays;
long earthPopulation;
boolean done;
- 变量名:一个字母开头并由字母或数字构成的序列
- 字母:
- ’A’~’Z’
- ’a’~’z’
- ’_’
- ’$’
- 某种语言中表示字母的任何 Unicode 字符
- 不能使用 Java 保留字作为变量名
- 字母:
✅提示:可以使用 Character
类 的 isJavaldentifierStart 和 isJavaldentifierPart 来检查哪些 Unicode 字符属于 Java 中的“字母”。
✅提示:$ 虽然是一个合法的 Java 字符, 但不要在你自己的代码中使用这个字符。它只用在 Java 编译器或其他工具生成的名字中。
可以在一行声明多个变量(不提倡使用,逐一声明能提高程序可读性)
int i,j;//both are integers
🗒️注释:
可以使用变量名命名为类型的方式。
Box box; // "Box" is the type and "box" is the variable name
或
Box abox;
3.4.1 变量初始化
-
声明
-
初始化(赋值)
-
声明一个变量之后,必须用赋值语句对变量进行显式初始化, 千万不要使用未初始化的变量。
int vacationDays; System.out.println(vacationDays): // ERROR variable not initialized
-
要想对一个已经声明过的变量进行赋值, 就需要将变量名放在等号(=) 左侧, 相应取值的 Java 表达式放在等号的右侧。
int vacationDays; vacationDays=12;
-
可以将变量的声明和初始化放在同一行中。
int vacationDays = 12;
-
在 Java 中可以将声明放在代码中的任何地方。
double salary = 65000.0; System,out.println(salary); int vacationDays = 12; // OK to declare a variable here
- 在 Java 中, 变量的声明尽可能地靠近变量第一次使用的地方, 这是一种良好的程序编写风格。
©️ C++ 注释:C 和 C++ 区分变量的声明与定义
int i = 10;
extern int i;
Java 中不区分变量的声明与定义。
3.4.2 常量
在 Java 中,利用关键字 final
指示常量
final 关键字修饰一般变量:
public class Constants {
public static void main(String[] args) {
final double CM_PER_INCH = 2.54;
double paperWidth = 8.5;
double paperHeight = 11;
System.out.println("Paper size in centimeters: " + paperWidth * CM_PER_INCH + " by " + paperHeight * CM_PER_INCH);
}
}
- final 修饰变量只能被赋值一次,被赋值后就不能更改
- 常量名使用全大写
public class Constants2 {
public static final double CM_PER_INCH = 2.54;
public static void main(String[] args) {
double paperWidth = 8.5;
double paperHeight = 11;
System.out.println("Paper size in centimeters: " + paperWidth * CM_PER_INCH + " by " + paperHeight * CM_PER_INCH);
}
}
final 关键字修饰类变量:
- 类常量定义在 main 方法外部,同一个类的其他方法可以使用这个常量
- 该常量声明为 public ,其他类也可以使用这个常量
©️ C++ 注释:const 是 Java 保留的关键字,但目前没有使用。在 Java 中使用final 定义常量。
3.5 运算符
- 在 Java 中,使用算术运算符 + 、 - 、* 、 / 表示加、减、乘、除。
- 参与 / 运算的两个操作数都是整数,表示整数输出;否则,表示浮点除法。
- 整数的求余操作(取模),使用 % 表示。
🗒️注释:可移植性是 Java 语言的设计目标之一。
无论在哪个虚拟机上运行,同一运算应该得到同样的结果。
对于浮点数的算术运算,实现这样的可移植性是相当困难的。
double 类型使用64位存储数值,而有些处理器使用80位浮点寄存器。
举例:
double w = x * y / z;
很多 Inter 处理器,先计算 x * y,将结果存储在80位的寄存器,再除以z并将结果截断为64位。
Java 虚拟机最初的规范规定所有的中间结果都必须进行截断(会导致溢出,截断操作需要消耗时间,实际计算速度比精确计算更慢)
为此,Java 程序设计语言承认了最优性能与理想结果之间存在的冲突,并给予了改进。
在默认情况下, 虚拟机设计者允许对中间计算结果采用扩展的精度。但是, 对于使用 strictfp
关键字标记的方法必须使用严格的浮点计算来生成可再生的结果。
strictfp 标记的方法必须使用严格的浮点计算来生成可再生的结果:
public static strictfp void main(String[] args)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律