Java笔记_5
概述和环境
源码文件
- 确保安装了
JDK
, 并且配置了环境变量 jdk/lib
目录中可以找到src.zip
, 这个压缩包包含了所有的公共类库的源码- 使用
jar xvf jdk/lib/src.zip
可以将src.zip
解压缩到当前目录下 - 如果是别的源码, 比如编译器, 原生方法, 虚拟机, 私有辅助类, 需要从
openjdk
那边拿到
控制台运行Java
- 一个包含
Main
函数的Java
类, 使用javac xxx.java
可以将xxx.java
文件编译为.class
文件 - 然后再使用
java xxx
, 不需要加.class
后缀即可直接运行这个编译后的文件
JShell
JDK 9
引入了另一种使用Java
的方法,就是"读取-评估-打印循环" (Read-Evaluate-Print Loop
,REPL
)- 输入一个表达式,
JShell
会评估输入, 打印结果, 并等待下一个输入. 直接在控制台输入jshell
即可开始使用- 输入
"java".length()
就会返回字符个数$1 ==> 4
- 然后再输入
4 * $1 + 1
, 会返回$2 ==> 17
- 并不需要手动输入
System.out.println()
也可以直接返回结果, 并自动存储变量 - 也可以手动指定变量名, 例如
int ans = 42
, 会返回结果ans ==> 42
- 输入
Java
规范
- 类名需要驼峰: 首字母大写, 后面每个单词的首字母均大写
- 文件名必须和文件内的公共类相同
main
函数一定需要在public
类中, 虚拟机从main
函数开始执行.main
方法总是静态的main
函数返回值为0
, 如果需要以其他的返回值返回, 需要使用System.exit(nums)
- 变量的声明尽可能靠近使用变量的地方
JDK 10
开始, 对于局部变量, 可以使用var
关键字声明, 这样可以从变量的初始值推断出他的类型var d = 12; // d is an int
var s = "12"; // s is a String
Java
中不区分变量的声明和定义
类型
Java
具有8种基本类型, 其中4种整型, 2种浮点类型, 1种字符类型char
(用于表示Unicode
编码), 1种boolean
类型- 同时
Java
具有一个表示任意精度的算数包, 大数big number
是一个Java
对象, 而不是基本Java
类型
整型
Java
的int
无论在什么环境下都是4 Bytes
, 可以表示- 可以给数字加上下划线, 在编译时会自动去除, 方便源码阅读:
12_000_000_000
Java
中没有无符号类型, 如果确实需要无符号数, 比如short
表示范围需要在0~255
之间的话, 进行计算的时候可以使用Byte.toUnsignedInt(b)
来得到一个无符号整数
浮点型
- 一般都使用
8 Bytes
的double
类型, 而不是4 Bytes
的float
类型 - 可以使用十六进制表示浮点数字面量, 例如可以写成
0x1.0p-3
- 这里
0x
表示十六进制,p
表示指数. 不是e
是因为e
在十六进制中了,-3
表示十进制的-3
次方, 基数为2
- 这里
- 浮点数溢出的三种情况:正溢出,负溢出和
NaN
,如果正数/0就是正溢出,反之负溢出;如果就是NaN
Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NaN
表示三个特殊的值, 基本不用if (x == Double.NaN)
永远为假, 因为NaN
是永远不会和其他值相同, (Double.NaN
也不会和Double.NaN
相同)- 如果需要判断
x
是否为NaN
, 可以使用if (Double.isNaN(x))
- 如果需要判断
- 如果需要精确表示浮点数的话, 需要使用
BigDecimal
类 - 整数除
0
产生异常, 浮点数除0
得到结果NaN
字符类型
char
类型可以表示十六进制值, 范围从\u0000~\uFFFF
- 需要注意注释中尽量不要出现
Unicode
字符, 例如// \u000A is a newline.
这句话会产生一个语法错误, 因为读程序时会将\u000A
转换为一个换行符// look inside c:\user
这里也是会报错的, 因为\u
后面没有跟着4
位十六进制数
- 原本
Unicode
字符不超过65536
个, 所以Java
设置了char
类型只有16
位 - 后来字符放不下了,
Java
设置码点来解决问题, 指一个编码表中某个字符对应的代码值 - 码点采用十六进制编写, 加上前缀
U+
, 比如U+0041
就是A
的码点 Unicode
的码点可以分为17
个代码平面, 第一个代码平面被称为基本多语言平面, 包括了码点范围是U+0000~U+FFFF
- 其余
16
个平面的码点范围是U+10000~U+10FFFF
- 不要在
Java
代码中使用char
类型, 一般将字符串作为抽象数据类型处理
布尔类型
Java
的整型和布尔值不能相互转换
常量
- 使用
final
关键字定义的, 只能被赋值一次, 不能再更改, 一般用全大写命名 - 可能需要创建一个常量在类中的多个方法中使用, 称为类常量, 可以使用
static final
设置一个类常量 const
是Java
保留的一个关键字, 但是目前并没有使用
1 | public class A { |
枚举类型
1 | enum Size {SMALL, MEDIUM, LARGE, EXTRA_LARGE}; |
循环移位
>>
表示左移, 使用符号位填充;>>>
表示左移, 永远使用0
填充<<
表示右移; 不存在<<<
- 所有移位的右操作数都需要对32取模, 如果左操作数是
Long
类型, 则右操作数需要对64取模1
2
3
4
5int i = 1;
long j = 1;
1 << 35; // 与 1 << 3等价, 结果为8
i << 35; // 与 1 << 3等价, 结果为8
j << 35; // 与 1 << 35等价, 结果为34359738368
字符串
Java
中字符串就是Unicode
序列, 比如"Java\u2122"
由五个Unicode
字符组成Java
没有内置的字符串类型, 标准Java
类库中提供了一个预定义类- 任何
Java
对象都可以转换为字符串, 所以"PG" + 12 = "PG12"
- 如果多个字符串使用界定符分割的话, 可以使用静态
join
方法1
String all = String.join("/", "S", "M", "I"); // all = "S/M/I"
JDK 11
中提供了repeat
方法1
String rep = "J".repeat(3); // rep = "JJJ"
Java
中字符串不可变, 如果需要修改一个字符串的一部分, 需要先使用substring
提取字符串不需要修改的部分, 然后加上其他修改后的结果字符串
- 字符串不可变每次都需要生成新的字符串, 会降低效率, 但是编译器底层可以实现字符串共享
- 开发者认为字符串共享带来的收益比修改字符串带来的收益明显, 因为往往需要比对字符串是否相同, 修改频率较少
- 只会共享字符串字面量, 由
+
或者substring
得到的字符串无法共享 - 因此比较两个字符串相等的时候务必使用
"A".equals("A")
, 如果使用==
, 则会比较两个字符串引用是否相等 - 如果要检查字符串不是空串也不是
null
的话, 需要先检查null
:if (s != null && s.length() != 0)
, 否则如果字符串为null
的话, 调用这个字符串的length()
函数会报错
-
Java
中最常用的Unicode
由一个代码单元表示, 但是辅助字符需要两个代码单元, 所以如果使用charAt()
, 会返回指定索引的代码单元- 如果正好某个索引需要两个代码单元, 但是使用
charAt()
指定了前一个索引, 就会出现问题. 因此,charAt()
一般不要用 - 为了测试, 需要提前设置
cmd
窗口内编码格式为Unicode
, 在cmd
内输入chcp 65001
将当前窗口的编码格式切换为Unicode
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20public static void main(String[] args) {
String s = "123\uD835\uDD46";
System.out.println("当前字符串是: " + s);
System.out.println("s.length() = " + s.length());
System.out.println("使用s.charAt()打印每一个元素: ");
for (int i = 0; i < s.length(); i ++) {
System.out.print(s.charAt(i) + " ");
}
System.out.println();
System.out.print("s的实际长度(码点个数)为: ");
int trueLen = s.codePointCount(0, s.length());
System.out.println(trueLen);
System.out.println("使用s.codePointAt()打印每一个元素: ");
for (int i = 0; i < trueLen; i ++) {
System.out.print(s.codePointAt(s.offsetByCodePoints(0, i)) + " ");
}
}- 上面代码的输出结果为:
- 上面代码的输出结果为:
- 如果正好某个索引需要两个代码单元, 但是使用
-
如果需要拼接多个较短的字符串, 可以使用
StringBuilder
StringBuffer
效率不如StringBuilder
, 不过StringBuffer
可以支持多线程添加删除字符- 如果所有操作都在单线程, 则使用
StringBuilder
-
JDK 15
中存在文本块, 以三个引号开头结尾, 可以更加方便的写换行, 例如1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16String a =
"""
Hello
World
""";
String b = "Hello\nWorld\n";
// a == b
// 文本块最适合放SQL语句或者HTML语句, 但是如果所有的反斜线都需要转义
// 如果不转义就会变成不换行
String c =
"""
Hello\
World
""";
String d = "HelloWorld\n";
// c == d
输入输出
- 如果是密码相关的内容, 建议不要使用
println()
, 可以使用Console.readPassword()
printf("%+f", d)
可以打印d
的正负号printf(%,f, d)
可以对d
增加三个数一组的分割符printf("%1$d,%1$x", d)
分别以十进制和十六进制打印第一个参数d
printf("%d%<x", d)
分别以十进制和十六进制打印同一个数- 使用
String.format
方法可以格式化字符串, 不打印输出1
2
3String message = String.format("Hello, %s. Next year, you'll be %d", name, age + 1);
// JDK 15版本以后可以使用下面这种更加简单的方法
String message = "Hello, %s. Next year, you'll be %d".formatted(name, age + 1); - 写入文件使用
1
2
3
4
5PrintWriter out = new PrintWriter("tmp.txt", StandardCharsets.UTF_8);
out.write("werwr");
out.flush();
// 如果tmp.txt不存在, 则会自动创建一个
// 写入以后需要使用flush才能保存
控制流程
Java
中两个嵌套的块不能重复定义相同的变量- 在
for
循环中不能检测了两个浮点数是否相等, 因为误差的存在, 可能会导致死循环
switch-case
1 | // 第一种 |
- 不能混用
:
和->
, 同时->
也不存在直通的行为 yield
也会终止switch
语句, 但是还会生成一个值switch
表达式的关键是生成一个值, 或者抛出异常, 不允许使用return
跳出
1 | int ans = switch(s) { |
1 | int nums = switch(s) { |
大数
1 | // 使用valueOf()静态方法可以将一个普通的数转换为大数 |
- 对于
BigDecimal
类, 总应该使用带有字符串参数的构造器生成. 尽管有BigDecimal(double)
, 但是传入的时候会产生浮点数精度误差 Java
不能通过编程实现运算符的重载, 所以只能使用add(), multiply()
等方法实现加减乘除Java
设计者只重载了+
来实现字符串拼接
数组
Java
中允许长度为0
的数组存在- 数组创建时, 数字数组初始化为
0
, 对象数组初始化为null
,boolean
数组初始化为false
- 如果想要打印数组a, 可以直接写
Arrays.toString(a)
, 这个返回值包含了数组中所有元素的字符串 - 如果想要快速打印一个二维数组, 可以使用
Arrays.deepToString(a)
1 | int[] a = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; |
数组拷贝
1 | int[] a = {1, 2, 3}; |
main
函数的参数, 是String[] args
, 接受一个字符串数组, 也就是命令行指定的参数java Message -h hello
这里面args[0]=-h
args[1] = hello
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Sangs Blog!