本文是《Java核心技术1》第10版 【Chap3 基本程序设计】 的要点总结。
8种基本数据类型
整型
- int: 4字节
- short: 2字节
- long: 8字节
- byte: 1字节
Java没有任何无符号的 int, long, short, byte
浮点型
- float: 4字节
- double: 8字节
表示溢出和出错的3个特殊浮点数值
正无穷
负无穷
NaN(不是一个数字)
double.isNaN 判断
不允许舍入误差,则要用 BigDecimal 类
char型
一些Unicode可以用一个 char 值描述,有的需要两个
转义序列 \u
可以出现在字符字面量或字符串中,会在解析代码前处理
Unicode
- 码点:与一个编码表中某个字符对应的代码值
- UTF16采用不同长度的编码表示所有Unicode码点
char类型是一个采用 UTF16编码表示的 Unicode码点的代码单元
建议不要使用 char 型(除非确实要处理 UTF16),最好用字符串
boolean
整形值和布尔值之间不能相互转换
变量
- 声明变量时,每个变量都有一个类型
- 保留字不可用于变量名
- 变量初始化
- 声明变量之后,必须用赋值语句显式初始化
- 与C++不同的是,Java不区分变量的声明和定义
- 常量
- 关键字 final
- 只能被赋值一次
- static final 可以设置类常量
运算符
算术运算符
+, -, *, /, %
- 整数被 0 除产生一个异常,浮点数被 0 除得到无穷大或 NaN
- 数学函数
import java.lang.Math
- sqrt, pow, floorMod
- sin, cos, tan, atan, atan2
- exp, log, log10
- Math.E, Math.PI
- 数值类型转换
- 无信息丢失
- byte -> short
- short -> int
- char -> int
- int -> long
- float -> double
- int -> double
- 有信息丢失
- int -> float
- long -> double
- long -> float
- 自动类型转换
- 有一个 double,另一个转换为 double
- 否则,有一个 float,另一个转换为 float
- 否则,有一个是 long,另一个转换为 long
- 否则,两个都转换为 int
- 强制类型转换
- 丢失信息的转换,需要 cast
Math.round
- 转换后超出了目标类型的表示范围,则会截断
- 扩展赋值运算符
+=, -=, *=, /=, %=
- 自增运算符
++, --
- 前缀形式和后缀形式
关系运算符
==, !=, <, >, <=, >=
&&, ||
三元运算符
cond ? expr1 : expr2
位运算符
&, |, ^, ~
<<, >>
-
>>>
用 0 填充高位;>>
用符号为填充高位 - 没有
<<<
- C++ 中
>>
对于负数生成的结果依赖具体实现
运算符优先级
[] . ()(方法调用)
! ~ ++ -- +(一元) -(一元) ()(强制类型转换) new
- 从右向左结合
* / %
+ -
<< >> >>>
< <= > >= instanceof
== !=
&
^
|
&&
||
-
?:
(从右向左结合) -
= += -= *= /= %= |= &= ^= <<= >>= >>>=
(从右向左结合)
枚举类型
- 变量取值只在有限集合内
- 枚举类型的变量只能存储给定的某个枚举值,或 null 值
控制流
- 没有 goto,但 break 可以带标签,其它基本与 C++ 基本一样
- 块作用域
- 块确定了变量的作用域
- Java不能在嵌套的两个块中声明同名变量,C++中是内层覆盖外层
- 条件语句
- 循环
- while
- for
- 多重选择 swtich
- 从与选项值相匹配的case标签处开始执行直到遇到break语句
- 没有相匹配的case标签,而有default子句,就执行这个子句。
- 如果在case分支语句的末尾没有break语句,那么就会接着执行下一个case分支语句。
- case标签
- 类型为char、byte、short或int的常量表达式
- 枚举常量
- 字面值常量
- 中断
- 普通 break 和 continue
- 带标签的break
- Java可以用带标签的break,跳出多重嵌套的循环。
- 标签必须放在希望跳出的最外层循环之前,并且必须紧跟一个冒号。
- 带标签的 continue
- 跳到与标签匹配的循环首部。
字符串
- 概念上讲,Java字符串就是Unicode字符序列
- Java没有内置的字符串类型,而是在标准 Java 类库中提供预定义类 String
- 子串
- substring
- 拼接
- 字符串与非字符串拼接,会先转换成字符串
- Java任何对象都可以转换成字符串
- join
- 不可变字符串
- String没有可以修改字符串的方法
- 缺点是提取,拼接低效
- 优点是编译器可以让字符串常量在堆中共享
- 只有字符串常量是共享的,+ 和 substring 等操作产生的结果并不共享
- 检测字符串是否相等
- equals
- equalsIgnoreCase
- == 判断的是字符串是否在同一位置上
- compareTo 类似于 C 语言的 strcmp
- 空串
- str.length() == 0 或者 str.equals(“”)
- Java 对象,有串长度(0),和内容(空)
- null串
- 没有任何对象与该变量关联
- str == null
- 码点和代码单元
- char类型是一个采用 UTF16编码表示的 Unicode码点的代码单元
- length() 返回采用 UFT16 编码表示的给定字符串所需的代码单元数量
- 要得到实际长度,也就是码点数量,用 codePointCount()
- charAt() 返回位置 n 的代码单元
- 获得第 i 个码点
int idx = offsetByCodePoints(0, i);
int ch = str.codePointAt(idx)
- 由于有些UTF16表示的字符需要两个代码单元,最好不用 char 类型
- 遍历字符串,查看每一个码点
int i = 0;
int p = str.codePointAt(i);
if(Character.isSupplementaryCodePoint(p))
i += 2;
else
i++;
- codePoints 方法生成一个int值的流,每个int对应一个码点
int codePoints = str.codePoints().toArray();
- 码点数组转换为字符串
String str = new String(codePoints, 0, codePoints.length);
- String API
- 由许多小串构建字符串
StringBuilder builder = new StringBuilder();
builder.append(ch);
builder.append(str);
String completedString = builder.toString()
输入输出
- Scanner 读取输入
- 构造 Scanner 对象,与标准输入流 System.in 关联
Scanner in = new Scanner(System.in);
- 读取一行
String name = in.nextLine();
- 取一个单词
String firstName = in.next();
- 取一个整数
int age = in.nextInt()
- 取一个浮点数
int age = in.nextDouble()
- Console 读取输入
- Scanner 不适合从控制台读密码
Console cons = System.console();
String username = cons.readLine("User Name: ");
char[] passwd = cons.readPassword("Password: ");
- 为了安全起见,返回的密码存放在一维字符数组中,而不是字符串中。在对密码进行处理之后,应该马上用一个填充值覆盖数组元素
- Console 只能读取一行输入。没有能读取一个单词或数值的方法。
- 格式化输出
System.out.print(x)
- 以x对应的数据类型所允许的最大非0数字位数打印输出x
System.out.printf(x)
- 沿用了C语言库函数中的printf方法
-
String message = String.format(...);
创建格式化字符串而不打印输出
- Scanner 文件输入
- 用File对象构造一个Scanner对象
- Scanner in = new Scanner(Paths.get(“file.txt”), “UTF-8”);
- Scanner 文件输出
- 用PrintWriter对象构造一个Scanner对象
- Scanner out = new PrintWriter(“file.txt”, “UTF-8”);
- 命令行重定向
- java Proj < file.txt > output.txt
大数值
- java.math.BigInteger 和 java.math.Decimal
- 普通数值转换为大数值
BigInteger a = BigInteger.valueOf(100);
- 与 C++ 不同,Java 没有运算符重载
add, multiply, subtract, divide, mod, compareTo, valueOf
数组
数组是一种数据结构,存储同一类型值的集合,且可通过下标访问
声明
int[] a;
初始化
a = new int[100];
- 数字数组,所有元素都初始化为0。
- boolean数组,初始化为false。
- 对象数组,初始化为一个特殊值null
a = {2, 3, 5, 7};
- 初始化匿名数组
new int[] {2, 3, 5, 7}
可以用在方法的返回值
- 长度为 0 的数组
new int[0]
长度
a.length
数组一旦创建,不能再改变大小,如果要改变大小,用数组列表 ArrayList
for each 循环
for(variable: collection) statement
collection 是实现了 Iterable 接口的类对象
数组拷贝
int[] b = a;
- 在Java中,允许将一个数组变量拷贝给另一个数组变量。
- 这时,两个变量将引用同一个数组
- 如果要将所有值拷贝到新数组,用 Arrays 类的 copyOf 方法
命令行参数
- main 接收一个字符串数组 args
- 与C++不同,程序名并不在args数组中
数组排序
Arrays.sort()
快速打印
System.out.println(Arrays.ToString(a));
多维数组
- 声明
double[][] a;
- 初始化
a = new double[100][100]
- for each
for(double[] row: a)
for(double val: row)
...
- 快速打印
System.out.println(Arrays.deepToString(a));
- 不规则数组
- Java实际上没有多维数组,只有一维数组。多维数组被解释为“数组的数组。
- 由于多维数组实际上是一维数组,可以方便地构造不规则数组
Java数组类似于C++中分配在堆上的数组指针
- 一维
- Java:
double[] a = new double[10];
- C++:
int* a = new int[100];
- 二维
- Java:
double[][] a = new double[10][5];
- C++:
double** a = new double*[10];