1 Java数据类型
Java是一种强类型语言,这就意味着每一种变量在申明时必须确定类型。在Java中有 8 种基本类型,其中有 4 种整型(short
、int
、long
、byte
), 2 种浮点类型(float
、double
), 1 种用于表示Unicode编码的字符单元的字符类型(char
)和 1 种用于表示真值的类型(boolean
)。
1.1 整型
整型:用于表示没有小数部分的数值
类型 | 存储 | 范围 |
---|---|---|
long | 8字节 | -9,223,372,036,854,775,808 ~ 9,223,372,036,854,775,807 |
int | 4字节 | -2,147,483,648 ~ 2,147,483,647 |
short | 2字节 | -32,768 ~ 32767 |
byte | 1字节 | -128 ~ 127 |
进制 | 表示 |
---|---|
二进制 | 0B或0b |
八进制 | 0 |
十进制 | |
十六进制 | 0X或0x |
注意:
1. 在Java中整型的范围和所占的存储空间与机器无关;
2. 长整型数值在赋值的时候后面要添加一个L
用来标识;
3. 整型数值可以使用多种进制表示,常用的进制表示有:十六进制(0x
)、八进制(0
)、二进制(0B
);
4. 为了提高代码的可读性,数字可用下划线来分割,例如1_000_000
来表示100万。
1.2 浮点类型
浮点类型:用于表示有小数部分的数值,常用的类型是double型,float型难以满足需求,且浮点数值不能用于金融计算中
类型 | 存储 | 范围 |
---|---|---|
double | 8字节 | 大约 ±1.79769313486231570E+308 ± 1.79769313486231570 E + 308 (有效位数为6 ~ 7位) |
float | 4字节 | 大约 ±3.40282347E+38F ± 3.40282347 E + 38 F (有效位数为15位) |
注意:
1. double类型的精度较高,大多数程序都采用double类型,float类型的优势是所占空间小;
2. float类型的数值在赋值的时候后缀F
或f
,没有后缀的将自动装箱成double类型;
3. 浮点类型数据在运算的时候无法保证精度,因此在精度要求较高的运算中应使用大数值类型。
名称 | 表示 | 情境 |
---|---|---|
正无穷大 | Double.POSITIVE_INFINITY | 正整数除以0 |
负无穷大 | Double.NEGATIVE_INFINITY | 负整数除以0 |
不是一个数字 | Double.NaN | 0除以0 |
1.3 字符类型
char类型:用于表示单个字符,char类型的字面量值要用单引号括起来,char类型的值可以表示为十六进制值,其范围从\u0000到\uffff。
转义序列 | 名称 | Unicode值 |
---|---|---|
\b | 退格 | \u0008 |
\t | 制表 | \u0009 |
\n | 换行 | \u000a |
\r | 回车 | \u000d |
\” | 双引号 | \u0022 |
\’ | 单引号 | \u0027 |
\\ | 反斜杠 | \u005c |
注意:
1. 强烈建议不要在程序中使用char
类型,除非确实需要处理UTF-16
代码单元,最好将字符串作为抽象数据类型处理;
2. Unicode的转移序列会在解析代码之前得到处理,特别是\u
,可能会引起语法错误;
3. 字符类型的字面量值要用单引号括起来;
4. 字符类型可以使用单引号括字符的表示方式和十六进制转义字符表示;
5. Java采用Unicode编码来表示字符。
1.4 布尔类型
布尔类型(boolean):用来判定逻辑条件
注意:
1. boolean类型有两个值:true
、false
;
2. 整型值和布尔值之间不能进行相互转换。
1.5 字符串
Java字符串就是Unicode字符序列,字符串并不是基础数据类型,而是一个类(String
),采用双引号括起来的方式表示一个字符串实例。String类没有提供用于修改字符串的方法,String类的对象称为不可变字符串。
1.5.1 不可变字符串
- Java字符串中的字符不可修改,这样的做法虽然会降低效率,但是编译器可以让字符串共享
1.5.2 检测字符串是否相等
- 使用equals方法检测两个字符串是否相等;不可使用==运算符来检测;
- 使用equalsIgnoreCase方法检测两个字符串是否相等,而不区分大小写。
1.5.3 空串与Null串
- 空串是”“,是长度为0的字符串,它是一个Java对象
- Null串表示目前没有任何对象与该变量关联
//判断一个串是空串
if(str.length() == 0)
...
if(str.equals(""))
...
//判断一个串是Null串
if(str == null)
...
注意: 在使用String对象前,必须检查它是否为null,否则会出现错误
1.5.4 构建字符串
- Java提供了多种字符串的构建方式,下表列出各种方法之间的对比
表1-6 构建字符串
方式 | 优缺点 |
---|---|
字符串连接(+) | 效率低,时间开销大,空间开销大 |
StringBuilder | 线程不安全,效率高,空间开销小 |
StringBuffer | 线程安全,效率稍低,空间开销小 |
1.6 大数值
使用BigInteger和BigDecimal,用于实现任意精度任意长度的运算,一般在金融计算中采用。
1.7 数组
数组是一种数据结构,用来存储同一类型值的集合,通过一个整型下标可以访问数组中的每一个值,在声明数组变量时,需要指出数组类型和数组变量的名字。创建一个数字数组时,所有元素都初始化为0,boolean数组的元素会初始化为false,对象数组的元素则初始化为null。一旦创建了数组,就不能再改变它的大小,如果需要使用扩展数组,那么使用数组列表。
1.7.1 数组的声明、创建和初始化
- 在声明数组变量时,需要指出数组类型(数据元素类型紧跟[])和数组变量的名称:
int[] array;
- 创建数组,需要使用new运算符来创建数组:
array = new int[100];
,代码运行到创建数组语句时,数组的长度必须已经确定下来。 - 创建好数组之后,整型类型数组所有元素默认初始化为0,boolean数组默认初始化为false,对象数组的元素则初始化为null。
注意:
1. 数组的下标是从0开始到n-1;
2. 数组一经创建,大小不可变,内容可变;
3. 数组遍历可用遍历下标的方式和for each
循环,for each循环具有更高的遍历性能,但是只可访问不可修改。
1.7.2 数组拷贝
在Java中,允许将一个数组变量拷贝给另一个数组变量,这样两个变量指向同一个数组,如果需要拷贝的是一个备份,拷贝之后互不干扰,最好使用Arrays
类的copyOf()
方法。
1.7.3 多维数组
- 在Java中,声明一个二维数组:
double[][] table;
- Java实际上没有多维数组,只有一维数组,多维数组被解释为“数组的数组”,因此,二维数组的每一行可以拥有不同的长度。
1.8 变量、常量、类常量
1.8.1 变量
变量表示在编码时用到的单位数据,Java采用先声明后使用的方式来使用变量,变量名必须是以字母开头并由字母或数字构成的序列,字母包括A
~Z
、a
~z
、_
、$
或表示字母的任何Unicode字符(汉字)变量在使用前必须进行初始化,也就是赋值,变量的声明尽可能的靠近第一次使用的地方。
1.8.2 常量
常量采用关键字final
来指示,final
表示这个变量只能被赋值一次,一旦赋值之后,不能更改,习惯上变量名采用全大写。
1.8.3 类常量
在一个类中的多个方法中使用的常量,采用关键字static final
指示,类常量的定义位于main方法的外部。
2 Java运算符
在Java中,使用算数运算符 + 、 - 、 * 、 / 表示加、减、乘、除运算,当参与 / 运算的两个操作数都是整数时,表示整数除法;否则,表示浮点除法。整数的求余操作用 % 表示。
注意: 整数除以0将会产生一个异常,而浮点数除以0将会得到无穷大或NaN结果。
2.1 数学函数与常量
常用Math
类,可以达到最快的性能,如果为得到一个完全可预测的结果的话,使用StrictMath
类。
2.2 数值类型之间的转换
- 当两个变量在一个表达式中进行运算,且这几个变量的类型并不完全相同,Java将会按照下图的优先级别来进行变量类型的转换和统一
图2-1 数值类型之间转换关系
2.3 强制类型转换
强制类型转换的语法格式是在圆括号中给出想要转换的目标类型,后面紧跟待转换的变量名。进行数值的类型转换可能会丢失一些信息。
2.4 特殊运算符
类型 | 运算符 | 意义 |
---|---|---|
结合赋值运算符 | += 、-= | 同时实现运算和赋值 |
自增自减运算符 | ++ 、-- | 实现变量的自增或自减,有前缀和后缀两种形式,不同的是是否在执行该语句前变化 |
关系运算符 | != 、== 、< 、> 、<= 、>= | 判断两个数值之间的关系 |
boolean运算符 | && 、|| 、& 、| | 布尔运算 |
位运算符 | & 、| 、^ 、~ 、>> 、<< 、>>> | 按照位进行操作 |
三目运算符 | (expression)?if-true-statement : if-false-statement | 判断一个表达式的值并确定表达式的结果,是一个if else 语句的简化表达 |
类型相关运算符 | instanceof 、(type) | 类型检查或转换 |
注意:
1.&&
和||
是短路操作,如果第一个表达式能决定整个表达式的值,那么第二个表达式就不计算了;
2. &
和|
不是短路操作,所有的表达式都会计算;
3. >>>
运算符会用0填充高位,>>
用符号位填充高位,不存在<<<
运算符。
4. 对于低于int
类型(byte
、short
、char
)先自动类型转换为int
类型后再移位
5. 对于int
类型,如果移位数大于32
的话,系统先对移位数对32
求余,再移位
6. 对于long
类型,如果移位数大于64
的话,系统先对移位数对64
求余,再移位
7. >
、<
、>=
、<=
:只支持左右两边操作数是数值类型
8. /
整数除以整数结果会截断取整;整数不可以除0
,浮点数可以除0
,整数除0
将会产生一个异常,浮点数除0
将得到无穷大
或NaN
的结果
9.%
结果不一定总是整数(浮点求余),其它同/
10. ++
单目运算符,只能操作单个数值型,不能操作常量或表达式
3 Java控制流程
Java使用条件语句和循环结构确定控制流程
3.1 分支结构
3.1.1 条件语句
在Java中,条件语句的格式为if(condition) statement
,这里的条件必须用括号括起来。更一般的条件语句格式为:
if(condition1)
statement1;
else if(condition2)
statement2;
else
statement3;
注意:
1. 不要省略语句后面的花括弧;
2. 为了防止出现重复验证,优先把包含小范围的条件放在前面处理
3.1.2 多重选择:switch语句
switch
语句将从与选项值相匹配的case
标签处开始执行直到遇到break
语句,或者执行到switch
语句的结束处为止,如果没有相匹配的case
标签,而有default
子句,就执行这个子句。(注意:使用switch
语句的时候,注意每个分支之后确定有break
语句)
case
标签可以是:
- 类型为char、byte、short或int的常量表达式
- 枚举常量
- 字符串字面量
Scanner in = new Scanner(System.in);
int choice = in.nextInt();
switch(choice){
case 1:
...
break;
case 2:
...
break;
default:
...
break;
}
3.2 循环结构
3.2.1 while循环
while
循环执行一条语句,一般格式为:while(condition) statement
,如果希望循环体至少执行一次,则采用do while
循环语句:do statement while(condition)
。
3.2.2 for循环
for
循环语句是支持迭代的一种通用结构,利用每次迭代之后更新的计数器或类似的变量来控制迭代次数。for
语句的第1部分常用语对计数器初始化,第2部分给出每次新一轮循环执行前要检测的循环条件,第3部分指示如何更新计数器。1for1循环中各个部分之间用分号间隔开,各部分内不局限于一条语句,各条语句之间逗号间隔。
3.3 中断控制流程语句
break
语句
- 不带标签的
break
语句,用于退出循环语句; - 带标签的
break
语句,用于跳出多重嵌套的循环语句;
- 不带标签的
continue
语句
continue
语句用于中断正常的控制流程,将控制转移到最内层循环的首部;- 带标签的
continue
语句,将跳到与标签匹配的循环首部。
return
语句:直接结束整个方法
//跳出循环
while(condition1){
if(condition2)
break;
}
//跳出多重循环嵌套,直接到循环体的结尾
break_label:
while(condition1){
while(condition2){
if(conditon3)
break break_label;
}
}