读后笔记 -- Java核心技术(第11版 卷I )Chapter3 Java 的基本程序设计结构
Java 语言规范: https://docs.oracle.com/javase/specs/
3.2. 注释
Java 注释类型:
1)单行注释: // like this 2)多行注释(不能嵌套): /* like this */ 3)文档注释: /** * This is the first sample program in Core Java * @version 1.0 2002/1/1 * @author Gary Cornell */
3.3 数据类型
Java 8种基本数据类型(Java 是强类型语言) | ||
整型 |
int : 4字节 -2 147 483 648 ~ 2 147 483 647 (刚好超过 20 亿) short: 2字节 -32 768 ~ 32 767 long: 8字节 -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 807 byte: 1字节 -128 ~ 127 |
L/l: 长整型 0x/0X: 十六进制 0b/0B: 二进制 1_000_000: 数字加下划线,表示100万 * 八进制不建议用,数字前加0,容易混淆 |
浮点类型 |
float: 4字节 大约 ± 3.402 823 47E+38F (有效位数为 6 ~ 7 位) double: 8字节 大约 ± 1.797 693 134 862 315 70E+308 (有效位数为 15 位)
|
F/f: float类型 (很少使用,除非某些方法要求) D/d: double类型(没有F后缀,默认类型) 特殊常量: 1)Double.POSITIVE_INFINITY, Double_NEGATIVE_INFINITY 和 Double.NaN , 实际很少遇到,可使用: if(Double.isNaN(x)) // check whether x is "not a number"
2)System.out.println(2.0-1.1) 将打印 0.8999999999999999,因为二进制系统表示浮点数值 导致的舍入误差。如计算中不允许有任何舍入误差,应使用 BigDecimal 类 |
char 类型 |
char 类型的字面量值要用 '' 括起来,如 'A' 可表示为十六进制,其范围从 \u0000 ~ \Uffff |
特殊字符的转义序列:(转义序列 -- Unicode值) \b--\u0008 \t--\u0009 \n--\u000a \r--\u000d \''--\u0022 \'--\u0027 \\--\u005c ** 当心注释中的 \u ,如: // Look inside c:\users => 编译失败 // \u000A is a new line => 编译失败,读程序时,\u000A 已经转为换行符。 Unicode 转义序列会在解析代码之前得到处理。 |
boolean 类型 | true, false |
整数值和布尔值之间不能相互转换, 如 if (x = 0) // oops... meant x ==0,c++可编译运行,其结果总是false,而java不能编译 |
3.4 变量
3.4.1 变量初始化
- 声明后,必须显式初始化;
- 声明尽可能靠近第一次使用的地方(良好习惯);
- 不区分变量的声明与定义【C/C++区分定义和声明: int i = 10; //定义 extern int i; //声明 】;
注意:
- 1)大小写敏感;
- 2)不提倡一行声明多个变量;
3.4.2 常量
- final: 该变量只能被赋值一次;常量名使用全大写。
- static final:类常量,定义位于 main 方法的外部
- public: 一个常量被声明为 public,其他类的方法也可以使用这个常量
public class Constants2 { public static final double CM_PER_INCH = 2.54; // final:常量,static final:类常量(被一个类中的多个方法使用) 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) ; } }
3.5 运算符
3.5.1 /0 的结果:
- 整数 除以 0 => 异常;
- 浮点数 除以 0 => 无穷大 或 NaN
3.5.3 类型转换。
- 实线:数据无损;
- 虚线:有可能精度损失
当用一个二元运算符连接两个值时,将向表示更大数值的类型进行转换。 double > float > long > int
long n = 100; float ff = 200; float hh = n + ff; // long hh = ff + n; => error
3.5.4 强制类型转换
double x = 9.997; int nx = (int) x; // 强制转换,nx = 9 int nx = (int) Math.round(x); // 对浮点进行舍入运算, nx =10。因为 round 返回的是 long 类型,所以需要 (int) 显式强转
3.5.6 自增/减
int m = 7; int n = 7; int a = 2 * ++m; // now a is 16, m is 8 => 先更新变量值,再计算 int b = 2 * n++; // now b is 14, n is 8 => 先计算,再更新变量值 // ** 不建议在表达式中使用 ++/--
优先级 | 运算符分类 | 结合顺序 | 运算符 |
由 高 到 低 |
分隔符 | 左结合 | . [] (方法调用 ) ; , |
一元运算符 | 右结合 | ! ++ -- - ~ | |
算术运算符 移位运算符 |
左结合 | * / % + - << >> >>> | |
关系运算符 | 左结合 | < > <= >= instanceof(Java 特有) = = != | |
逻辑运算符 | 左结合 | ! && || ~("not") &("and") |("or") ^("xor") | |
三目运算符 | 右结合 | 布尔表达式?表达式1:表达式2 | |
赋值运算符 | 右结合 | = *= /= %= += -= <<= >>= >>>= &= *= |= |
*** 不确定优先级时,用 () 来处理
5. 枚举
// 自定义枚举类型 enum Size (SMALL, MEDIUM, LARGE, EXTRA_LARGE }; // 声明该类型的变量 Size s = Size.MEDIUM;
3.6 字符串
- substring: 子串;
- +: 拼接;
- .join(): 使用定界符拼接字符串; String all = String.join(" / ", "S", "M", "L", "XL"); // all: "S / M / L / XL"
- equals() / equalsIgnoreCase:检测两个字符串是否相等(区分/不区分大小写)。
- !! equals:比较值
- ==: 比较对象地址
// 3.6.5 空串与 null 串 "" :空串; // str1 = ""; str1.length() => 0 null:null 串 // str1 = null; str1.length() => NullPointerException if (str.length() == 0) 或 if (str.equals("")) // 1)空串 if (str == null) // 2)null; if (str != null && str.length() != 0) // 3)字符串不是 null 也不是空串
// 3.6.6 码点与代码单元 // 1. 字符串 转 码点数组 int[] codePoints = str.codePoints().toArray(); // 2. 码点数组 转 字符串 String str = new String(codePoints, 0, codePoints.length);
// 3.6.9 String 类对象是不可变的(immutable),所以需要有一个类(Stringbuilder)来处理如键盘输入的场景 // step1: 构建一个空的字符串构建器 StringBuilder builder = new StringBuilder();
// step2: 添加内容 builder.append(ch); builder.append(str);
// step3:构建字符串 String completedString = builder.toString();
3.7 输入输出
Scanner in = new Scanner(System.in); // 它有4个有用的方法: nextLine, next, nextInt, nextDouble // 接受字符串 String name = in.nextLine(); // 接受数值 int age = in.nextInt();
printf 的转换符,如:System.out.printf("%,.2f", 10000.0 / 3.0); // 3333.33 |
||||||
转换符 | 类型 | 举例 | 转换符 | 类型 | 举例 | |
d |
十进制整数
|
159 | s |
字符串
|
Hello
|
|
x |
十六进制整数
|
9f | c |
字符
|
H | |
o |
八进制整数
|
237 | b |
布尔
|
True | |
f |
定点浮点数
|
15.9 | h |
散列码
|
42628b2
|
|
e |
指数浮点数
|
1.59e+01
|
tx 或 Tx
|
日 期 时 间
(T 强制大写)
|
已经过时, 应当改为使用
javaJime 类,参见卷 II 第 6章
|
|
g |
通用浮点数
|
一
|
% |
百分号
|
% | |
a |
十六进制浮点数
|
0xl.fccdp3
|
n |
与平台有关的行分隔符
|
一
|
printf 的 标志,如: Systtem.out.prinf("%(,.2f", -1000.0 / 3.0) // (3333.33)
|
||||||
标 志
|
目 的 | 举 例 | 标 志 | 目 的 | 举 例 | |
+ |
打印正数和负数的符号
|
+3333.33
|
, | 添加分组分隔符 | 3,333.33 | |
空格 |
在正数之前添加空格
|
| 3333.33|
|
# ( 对于 f 格式) | 包含小数点 | 3,333. | |
0 |
数字前面补 0
|
003333.33
|
# (对于 x 或 0 格式) | 添加前缀 Ox 或 0 | Oxcafe | |
- |
左对齐
|
13333.33 |
|
$ |
给定被格式化的参数索引。例如, %l $d,%l$x
将以十进制和十六进制格式打印第 1 个参数
|
159 9F | |
( |
将负数括在括号内
|
( 3333.33 )
|
< |
格式化前面说明的数值。 例如,%d%<X 以十进制和
十六进制打印同一个数值
|
159 9F |
System.out.printf("%,.2f", 10000.0 / 3.0); System.out.printf("%8.2f", 10000.0 / 3.0);===== output ==== 3,333.33 // 1)保留小数点2位;2)千分位;3)实际位数 3333.33 // 1)保留小数点2位;2)包含小数点8位,不足的补空格
3.7.2 格式化:
1)参数格式化
// %1$:是对后面的第1个参数格式化, %2$:对第2个参数(new Date())的结果格式化,以 t 开始 + 日期/时间的转换符
// 索引 从 1 开始 System.out.printf(Locale.ENGLISH, "%1$s %2$tB %2$te, %2$tY", "Due date: ", new Date()); // Due date: December 21, 2021
2)Use String.format if you don't want to print:
String message = String.format("Hello, %s. Next year, you'll be %d", name, age);
3)格式说明符
3.7.3 文件输入输出
// 读取文件 // // in Java 7 and 10, we need to use Paths.get(); after later version, we should use Path.of() Scanner in = new Scanner(Path.of("C:\\test.robot"), StandardCharsets.UTF_8); // 写入文件 PrintWriter out = new PrintWriter("myfile.txt", StandardCharsets.UTF_8); out.println(...); // Need to tag main like this: public static void main(String[] args) throws IOException { Scanner in = new Scanner(Path.of("C:\\test.robot"), StandardCharsets.UTF_8); ... }
// 一个有用的方法,获取当前目录 String dir = System.getProperty("user.dir");
3.8 控制流程
public static void main(String[] args) { int n; { int k; int n; // Error -- can't redefine n in inner block } }
3.8.2 if (condition) statement
3.8.3 while
- while (condition) statement
- do statement while (condition); // 1)do 至少执行一次; 2)后面有一个 “;”
3.8.4 for (int i = 1; i <= 10; i++)
- 1)如要使用最终的值,需在 for 循环外部定义。 int i; for (i = 1; i <= 10; i++)
- 2)for 循环中 不要使用 浮点数
3.8.5 switch(较少使用)
- 1)每个 case 后面需要跟一个 break; 否则会一直往下执行
- 2)case 标签可以是:
- 类型为 char、byte、short 或 int 的常量表达式;
- 枚举常量;
- 字符串字面量(Java SE 7 开始);
3.9 大数
- BigInteger:实现任意精度的整数运算;
- BigDecimal:实现任意精度的浮点数运算;【相对比较常用,float 因为有精度问题】
BigDecimal bigDecimal1 = new BigDecimal("0.1"); BigDecimal bigDecimal2 = new BigDecimal(0.1); // 输出 0.1 => 方式: 1)new BigDecimal("str"), 2)使用 BigDecimal.valueOf(0.1); System.out.println("bigDecimal1: " + bigDecimal1); // 输出 0.1000000000000000055511151231257827021181583404541015625 System.out.println("bigDecimal2: " + bigDecimal2);
* 不能使用 +,* 计算,换成 add,multiply
BigInteger lotteryOdds = BigInteger.valueOf(1); for (int i = 1; i < k; i++) { lotteryOdds = lotteryOdds.multiply(BigInteger.valueOf(n - i + 1)).divide(BigInteger.valueOf(i)); }
3.10 数组
数组:存储相同类型值的序列。
3.10.1 声明:
int[] a = new int[100]; // var a = new int[100];
数组初始化:
- 1)数字数组,初始化值 0;
- 2)boolean数组,初始化值 false;
- 3)对象数组(如字符串数组),初始化值 null;
数组创建后,不能改变大小(array.length())。如运行过程中可扩展数组,则使用另外一个数据结构 array list
数组初始化及匿名数组
// 1)初始化数组 int[] smallPrimes1 = {2, 3, 5, 7, 11, 13}; // 2):new int[] {,,}:初始化一个匿名数组,然后赋值给另一个数组 int[] smallPrimes2 = new int[] {17, 19, 23, 29, 31, 37}; //初始化一个长度为 0 的数组 new int[0]
3.10.3 for each 循环(泛型 for 循环): for (variable : collection) statement
int[] a = new int[20]; for (int i = 0; i < 20; i++) { a[i] = i; } // 方式一:传统 for 循环打印 for (int i = 0; i < 20; i++) { System.out.println(a[i]); } // !!! 方式二:for each 打印 for (int num : a){ System.out.println(num); } // 方式三:Arrays.toString 方式打印 System.out.println(Arrays.toString(a));
3.10.4 数组 copy 及排序 sort
// 数组排序(无论是 数值数组 还是 字符串 数组) Arrays.sort(luckyNumbers);
public class CopiedArray { public static void main(String[] args) { int[] smallPrimes = {2, 3, 5, 7, 11, 13}; // 1)(浅copy,“=”)指向同一个地址,修改内容时,两个数组都被改 int[] luckyNumbers = smallPrimes; luckyNumbers[2] = 6; // smallPrimes: [2, 3, 6, 7, 11, 13] System.out.println("smallPrimes: " + Arrays.toString(smallPrimes)); // luckyNumbers: [2, 3, 6, 7, 11, 13] System.out.println("luckyNumbers: " + Arrays.toString(luckyNumbers)); // 2)(深copy,"Arrays.copyOf()")复制数组,相对独立,修改一个时,不影响另外一个 // 另外,第二个参数为长度 < 原数组长度:引用指定的数据; =:全复制; >:多余的补默认值 int[] copiedLuckyNumbers = Arrays.copyOf(smallPrimes, smallPrimes.length); copiedLuckyNumbers[0] = 100; // smallPrimes: [2, 3, 6, 7, 11, 13] System.out.println("smallPrimes: " + Arrays.toString(smallPrimes)); // copiedLuckyNumbers: [100, 3, 6, 7, 11, 13] System.out.println("copiedLuckyNumbers: " + Arrays.toString(copiedLuckyNumbers)); } }
3.10.7 二维数组
// 1.1 声明二维数组 double[][] balances;
// 1.2 初始化二维数组
balances = new double[NYEARS][NRATES]; // 2. 初始化二维数组,如果知道数组元素,则不需要 new int[][] magicSquares = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} } // 打印二维数组。for each 循环不能自动处理二维数组的每一个元素。需要使用两个嵌套的循环 for (double[] row : balances) { for (double b : row) { System.out.printf("%10.2f", b); } System.out.println(); }
// 快速打印二维数组的数据,可以用
System.out.println(Arrays.deepToString(balances));
3.10.8 不规则数组
当需要不规则的数组时,只能单独地创建行数组
final int MAX = 10; // allocate triangular array // 1)定义不规则数组的最大行 int[][] odds = new int[NMAX + 1][]; for (int n = 0; n <= NMAX; n++) { // 2)定义每行的数组长度 odds[n] = new int[n +1]; }