一个简单的Java应用程序

  1. public class FirstSimple{
  2. public static void main(String[] args){
  3. System.out.println("Hello World!");
  4. }
  5. }

数据类型

Java中共有8种基本类型,其中有4种整型、2种浮点类型、1种字符类型和1种用于表示真值的boolean类型

整型

类型 存储需求 取值范围
int 4字节 -2 147 483 648 ~ 2 147 483 647(刚好超过20亿)
short 2字节 -32768 ~ 32767
long 8字节 -9 223 372 036 854 775 808 ~ 9 223 372 036 854 775 808
byte 1字节 -128 ~ 127
  • byte和short类型用于特定的应用场合,例如,底层的文件处理或者存储空间很宝贵时的大数组
  • 数字字面量可以加下划线让人易读,如1_000_000(或0b1111_0100_0010)编译时会去除下划线

浮点类型

类型 存储需求 取值范围
float 4字节 大约±3.402 823 47E+38F(有效位数为6~7位)
double 8字节 大约±1.797 693 134 862 315 70E+308(有效位数为15位)
  • 浮点数值不适用于无法接受舍入误差的金融计算,例如System.out.println(2.0-1.1)将打印出0.8999999999999999,此时应该使用BigDecimal类
  • 没有后缀f的浮点数(如3.14)默认为double类型

char类型

原用于表示单个字符,现在有些Unicode字符可以用一个char值描述,一些Unicode需要两个char值

转义序列 \b \t \n \r \“ \‘ \\
名称 退格 制表 换行 回车 双引号 单引号 反斜杠
Unicode值 \u0008 \u0009 \u00a \u00d \u0022 \u0027 \u005c
  • 不建议在程序中使用char类型,除非确实需要处理UTF-16代码单元
  • 转义序列\u可以出现在加引号的字符串外,例如main(String \u005B\u005D args)就等于main(String[] args)
  • 字符串\u0022+\u0022会转换为""+"",是一个空串
  • // \u000a is a newline会产生一个语法错误,因为读程序时\u00a0会替换为一个换行符
  • 与上面类似,//C:\users也会产生错误,因为\u后面并没有跟着4个16进制数

boolean类型

Boolean(布尔)类型有两个值:false和true,用于判定逻辑条件。整型值和布尔值之间不能进行相互转换。

变量与常量

变量声明

  • 变量名必须以字母开头并由字母或数字构成,java中的’字母’和’数字’的范围比大多数语言范围更大。字母包括表示字母的任何Unicode字符。
    变量名长度基本没有限制
  • 可以使用Character类的isJavaIdentifierStartisJavaIdentifierPart方法来检查哪些Unicode字符输入Java中的’字母’
  • 尽管$是一个合法的Java字符,但不要在自己的代码中使用它。它只用在Java编译器或其他工具生成的名字中
  • 不能使用单下划线’_’和Java保留字作为变量名

变量初始化

  • Java中可以将变量声明放在代码中的任何地方,但尽可能靠近变量第一次使用的地方

从Java10开始,对于局部变量,如果可以从变量的初始值推断它的类型,就不再需要声明类型,只需要使用关键字var而无需指定类型:

  1. var vacationDays = 12; //vacationDays是int类型的数据
  2. var greeting = "Hello"; //greeting是String类型的数据

常量

利用关键字final指示常量,例如final double PI = 3.14;final表示变量只能被赋值一次,赋值后不能被更改。常量一般使用全大写。

枚举类型

详细内容见5.6

运算符

运算符优先级

运算符 结合性
[] . ()(方法调用)
! ~ ++ — +(一元运算) -(一元运算) ()(强制类型转换) new
* / %
+ -
<< >> >>>
< <= > >= instanceof
== !=
&
^
&&
∣∣
?:
= += -= *= /= %= &= ∣= ^= <<= >>= >>>=

数学函数与常量

Math类 API文档
Math类提供了一些方法使整数有更好的安全性,比如10亿乘以3(1,000,000,000*3)的结果是-1294967296,如果调用方法Math.multiplyExact(1000000000,3),就会产生一个异常。这样就可以捕获异常或让程序终止,而不是用错误的结果继续运行下去。

数值类型转换

  • Math.round可以对浮点数进行舍入运算,以便得到最接近的整数
  • int x; x += 3.5;是合法的,相当于(int)(x+3.5)
  • 不要在boolean类型与任何数值类型进行强制类型转换,防止发生一些常见的错误。用到时可以使用条件表达式b?1:0

字符串 String API

检测字符串是否相等

  • 可以使用equals方法检测两个字符串是否相等:s.equals(t)
  • 不区分大小写可以使用equalIgnoreCaseHeLlo.equalIgnoreCase("hello")
  • 一定不要使用==运算符检测两个字符串是否相等

    空串与Null串

    如果判断一个字符串既不是null也不是空串,需要用以下条件:
    if( str != null && str.length() != 0 )
    首先要检查str不为null,如果在null值上调用按方法,会出现错误。

    String常用API

    | 方法声明 | 功能描述 | | :—-: | :—-: | | char charAt(int index) | 返回给定位置的代码单元。除非对底层的代码单元感兴趣,否则不需要调用这个方法 | | int codePointAt(int index) 5 | 返回从给定位置开始的码点 | | int offsetByCodePoints(int startIndex, int cpCount) 5 | 返回从startIndex开始,cpCount个码点后的码点索引 | | int compareTo(String other) | 按照字典顺序,如果字符串位于other之前,返回一个负数;如果字符串位于other之后,返回一个正数;如果两个字符串相等,返回0 | | IntStream codePoints() 8 | 将这个字符串的码点作为一个流返回。调用toArray将它们放在一个数组中 | | new String(int[] codePoints, int offset, int count) 5 | 用数组中从offset开始的count个码点构造一个字符串 | | boolean empty() | 如果字符串为空或者由空格组成,返回true | | boolean blank() 11 | | | boolean equals(Object other) | 如果字符串与other相等,返回true | | boolean equalsIgnoreCase(String other) | 如果字符串与other相等(忽略大小写),返回true | | boolean startsWith(String prefix) | 如果字符串以prefix开头或以suffix结尾,则返回true | | boolean endsWith(String suffix) | | | int indexOf(String str) | 返回与字符串str或码点cp匹配的第一个子串的开始位置。从索引0或fromIndex开始匹配。如果在原始字符串中不存在str,则返回-1 | | int indexOf(String str, int fromIndex) | | | int indexOf(int cp) | | | int indexOf(int cp, int fromIndex) | | | int lastIndexOf(String str) | 返回与字符串str或码点cp匹配的最后一个子串的开始位置。从原始字符串末尾或fromIndex开始匹配 | | int lastIndexOf(String str, int fromIndex) | | | int lastIndexOf(int cp) | | | int lastIndexOf(int cp, int fromIndex) | | | int length() | 返回字符串代码单元的个数 | | int codePointCount(int startIndex, int endIndex) 5 | 返回startIndex和endIndex-1之间的码点个数 | | String replace(CharSequence oldString, CharSequence newString) | 返回一个新字符串。这个字符串用newString代替原始字符串中所有的oldString。可以用String或StringBuilder对象作为CharSequence参数 | | String substring(int beginIndex) | 返回一个新字符串。这个字符串包含原始字符串中从beginIndex到字符串末尾或endIndex-1的所有代码单元 | | String substring(int beginIndex, int endIndex) | | | String toLowerCase() | 返回一个新字符串。这个字符串将原始字符串中的大写字母改为小写,或将原始字符串中的所有小写字母改成大写字母 | | String toUpperCase() | | | String trim() | 返回一个新字符串。这个字符串将删除原始字符串头部和尾部小于等于U+0020的字符(trip)或空格(strip) | | String strip() 11 | | | String join(CharSequence delimiter, CharSequence... elements) 8 | 回一个新字符串,用给定的定界符连接所所有元素 | | String repeat(int count) 11 | 返回一个字符,将当前字符串重复count次 |

构建字符串 StringBuilder

有时需要由较短的字符串构建字符串,如果采用字符串拼接的方式,效率会比较低。每次拼接字符串时,都会构建一个新的String对象,既耗时又浪费空间。使用StringBuilder类可以避免这个问题的发生。

如果需要用许多小段的字符串来构建一个字符串,首先要构建一个空的字符串构建器:
StringBuilder builder = new StringBuilder();
调用append方法添加内容
builder.append("hello").append("world");
构建字符串完成时调用toString方法,就可以得到包含构建器中字符序列的String对象
String completedString = builder.toString();

StringBuilder类在Java5中引入。这个类的前身是StringBuffer,它的效率有些低,但允许多线程的方式添加或删除字符。如果所有字符串编辑操作都在单个线程中执行(通常都是这样),则应该使用StringBuilder。这两个类的API是一样的。

下面的API注释包含了StringBuilder类中的重要方法

方法名 说明
StringBuilder() 构造一个空的字符串构建器
int length() 返回构建器中的代码单元数量
StringBuilder append(String str) 追加一个字符串并返回this
StringBuilder append(char c) 追加一个代码单元并返回this
StringBuilder appendCodePoint(int cp) 追加一个码点,并将其转换为一个或两个代码单元并返回this
void setCharAt(int i, char c) 将第i个代码单元设置为c
StringBuilder insert(int offset, String str) 在offset位置插入一个字符串并返回this
StringBuilder insert(int offset, char c) 在offset位置插入一个代码单元并返回this
StringBuilder delete(int startIndex, int endIndex) 删除偏移量从startIndex到endIndex-1的代码单元并返回this
String toString() 返回一个与构建器或缓冲器内容相同的字符串

输入与输出

读取输入 Scanner

首先构造一个与“标准输入流”System.in关联的Scanner对象:
Scanner in = new Scanner(System.in);
Scanner类中常用方法:

方法名 说明
String nextLine() 读取输入的下一行内容
String next() 读取输入的下一个单词(以空格作为间隔符)
int nextInt() 读取并转换下一个表示整数的字符序列
double nextDouble() 读取并转换下一个表示浮点数的字符序列
boolean hasNext() 检测输入中是否还有其他单词
boolean hasNextInt() 检测是否还有下一个表示正数的字符序列
boolean hasNextDouble() 检测是否还有下一个表示浮点数的字符序列

从控制台读取密码:

  1. Console cons = System.console(); //Java6引入了Console类
  2. String username = cons.readLine("User name:");
  3. char[] passwd = cons.readPassword("Password:");

格式化输出

转换符 类型 示例 转换符 类型 示例
d 十进制整数 159 s 字符串 hello
x 十六进制整数 9f c 字符 H
o 八进制整数 237 b 布尔 true
f 定点浮点数 15.9 h 散列码 42628b2
e 指数浮点数 1.59e+01 tχ或Tχ 日期时间(T强制大写) 已过时,应使用java.time
g 通用浮点数(e和f中较短的一个) - % 百分号 %
a 十六进制浮点数 0x1.fccdp3 n 与平台有关的行分隔符 -
标识 目的 示例
+ 打印正数和负数的符号 +3333.33
空格 在正数之前添加空格 丨 3333.33丨
0 数字前面补0 003333.33
- 左对齐 丨3333.33 丨
( 将负数括在括号内 (3333.33)
, 添加分组间隔符 3,333.33
#(f格式) 包含小数点 3,333.
#(x或0格式) 添加前缀0x或0 0xcafe
$ 指定要格式化的参数索引,如%1$d %1$x按对应进制打印第一个参数 159 9F
< 格式化前面说明的数值,如%d%<x将以十进制和十六进制打印同一个数值 159 9F

可以使用printf输出格式化后的内容,如System.out.printf("name:%s,age:%d",name,age)
也可以使用静态的String.format创建格式化后的字符串,而不输出,如String message = String.format("name:%s,age:%d",name,age)

文件输入与输出

要读取文件,需要构造一个Scanner对象:
Scanner in = new Scanner(Paths.of("D:\\myfile.txt"),StandardCharsets.UTF_8);
要写入文件,需要构造一个PrintWriter对象:
PrintWriter out = new PrintWriter("myfile.txt",StandardCharsets.UTF_8);

数组

Java内存划分

  • 栈(Stack):存放方法中的局部变量,方法一定在栈中运行
  • 堆(Heap):new出来的都在堆中
  • 方法区(Method Area):存储.class相关信息,包含方法的信息
  • 本地方法栈(Native Method Area):与操作系统相关
  • 寄存器(PC Register):与CPU相关