简介

详细api方法可以查看:官方API文档
更多教程可以查看:官方教程文档

语法与 C、C++接近,且丢弃了 C++中很少使用的特性。此外,java 还不使用指针,而是引用,并提供了自动分配和回收内存空间,使得我们不用为内存管理而担忧。

运行环境,最好保证操作系统内存 1G 以上

基本数据类型

变量就是申请内存来存储值。

Java 的两大数据类型:

  • 内置数据类型
  • 引用数据类型

内置数据类型

类型 字节大小 大小(位) 最小值 最大值 默认值 包装类 备注说明
byte 1 8 -2^7 2^7 - 1 0 Byte 有符号整数
short 2 16 -2^15 2^15 - 1 0 Short 有符号整数
int 4 32 -2^31 2^31 - 1 0 Integer 有符号整数,最常用
long 8 64 -2^63 2^63 - 1 0L Long 需加 L 后缀(如 1000L)
float 4 32 ≈1.4E-45 ≈3.4E38 0.0f Float 单精度浮点,需加 f 后缀
double 8 64 ≈4.9E-324 ≈1.8E308 0.0d Double 双精度浮点(默认浮点类型)
char 2 16 0 2^16 - 1 ‘\u0000’ Character 无符号 Unicode 字符
boolean 1/8 1 false true false Boolean 大小取决于 JVM 实现

浮点数设计与整型不同,遵循IEEE 754 浮点数标准 ​​,不能用 2 的幂函数表示

引用数据类型

所有引用类型的默认值都是 null,如 String、array。

常量

在程序运行时,是不能被修改的。使用final进行修饰。

自动类型转换

在混合运算中,不同的类型是先转为同一类型,再进行计算,转换从低级到高级。

1
2
低  ------------------------------------>  高
byte,short,char—> int —> long—> float —> double

强制类型转换

如下:

1
2
3
int i1 = 123;
byte b = (byte)i1;//强制类型转换为byte
System.out.println("int强制类型转换为byte后的值等于"+b);

需要注意的是,强转是由高–>低,会出现溢出或者精度损失的情况。如上述代码,其中 i1,因为 byte 类型是八位,最大值是 127,当 i1=128 时,就会导致溢出。

隐含强制类型转换

只需要记住两点:

  • 整数的默认类型是 int。
  • 小数默认是 double 类型浮点型,在定义 float 类型时必须在数字后面跟上 F 或者 f。

怎么理解呢?就比如:float aa = 12.9;,这个赋值后面没有加 F/f,其实它完整的写法是:float aa = (float) 12.9;,中间有一个隐形的转换过程,因为小数 12.9 默认是 double 类型的。

变量类型

变量类型 声明位置 作用域 生命周期
局部变量 方法/构造块/代码块内部 仅在声明它的代码块内有效 从声明开始到代码块结束
实例变量 类内部(方法外部) 类实例内部有效 对象创建 → 对象被垃圾回收
静态变量 类内部 + static修饰 整个类范围(所有实例共享) 类加载时存在 → 程序结束
参数变量 方法/构造函数参数列表 整个方法/构造函数内部有效 方法调用开始 → 方法执行结束

参数变量

方法参数来那个量的值传递方式有两种:值传递引用传递

  • 值传递:基本类型都是采用值传递,它传递的是实际参数变量值的副本,不会对原本的参数变量造成影响。
  • 引用传递:对象类型采用引用传递方式传递值,它传递的是实际参数变量的引用(内存地址),当变量参数被赋予新的值时,会修改原始值。

访问修饰符

修饰符分为访问修饰符非访问修饰符

访问修饰符

访问修饰符 同类 同包子类 同包非子类 不同包子类 不同包非子类 说明
public 全局可见
protected 子类可见(即使跨包)
default 包内可见(默认修饰符)
private 仅类内可见

非访问修饰符

非访问修饰符 适用位置 用途说明
static 变量/方法/代码块 声明类级别成员(无需实例化即可访问)
final 类/方法/变量 禁止继承/重写/修改
abstract 类/方法 定义抽象类或抽象方法(要求子类实现)
synchronized 方法/代码块 线程同步(一次只允许一个线程访问)
volatile 变量 线程间可见性(变量直接读写主内存)
transient 变量 序列化时排除字段
native 方法 声明本地方法(用非Java语言实现)

运算符

算术运算符

运算符 名称 示例 说明
+ 加法 a + b 也用于字符串连接
- 减法 a - b
* 乘法 a * b
/ 除法 a / b 整数除法会截断小数
% 取模 10 % 31 计算余数
++ 自增 a++++a 前缀/后缀影响计算顺序
-- 自减 b----b 前缀/后缀影响计算顺序

关系运算符

运算符 名称 示例 说明
== 等于 a == b 比较基本类型值或对象引用
!= 不等于 a != b
> 大于 a > b
< 小于 a < b
>= 大于等于 a >= b
<= 小于等于 a <= b

逻辑运算符

运算符 名称 示例 说明
&& 逻辑与 a > 0 && b < 10 短路运算(前false则跳过计算)
`\ \ ` 逻辑或 `a < 0 \ \ b > 5` 短路运算(前true则跳过计算)
! 逻辑非 !valid 取反操作

位运算符

运算符 名称 示例 说明
& 按位与 mask & options 二进制位运算
`\ ` 按位或 `mask \ flags`
^ 按位异或 a ^ b 相同为0,不同为1
~ 按位取反 ~value 0变1,1变0
<< 左移 num << 2 相当于*4
>> 带符号右移 num >> 1 最高位补符号位
>>> 无符号右移 num >>> 3 最高位补0

其他运算符

类别 运算符 名称/作用 示例 说明
赋值运算符 = 赋值 int x = 5;
+= -= 复合赋值 a += 3; 等价于 a = a + 3
三元运算符 ? : 条件运算符 max = (a>b) ? a : b; 简化if-else
类型检查 instanceof 实例检查 obj instanceof String 检查对象类型
成员访问 . 点运算符 obj.method() 访问对象成员
优先级控制 () 括号 (a+b)*c 改变运算顺序

数组

数组是一块儿连续区域,分割为大小相同的元素块儿,查询速度快。
其中查询快是根据索引查询数据快:通过地址值和索引值定位,查询任意数据耗时相同
1.声明

1
2
3
dataType[] arrayRefVar;   // 首选的方法

dataType arrayRefVar[]; // 效果相同,但不是首选方法

2.创建

1
arrayRefVar = new dataType[arraySize];

1&2合起来就是:dataType[] arrayRefVar = new dataType[arraySize];
此外,还可以像这样:dataType[] arrayRefVar = {value0, value1, ..., valuek};

可以使用 java.util.Arrays 工具类,方便操作数组,其中最常用的就是,Arrays.sort(array),排序数组。

正则表达式

Java 提供了 java.util.regex 包,它包含了 Pattern 和 Matcher 类,用于处理正则表达式的匹配操作。

1
2
3
4
5
6
String line = "This order was placed for QT3000! OK?";
String pattern = "(\\D*)(\\d+)(.*)";
// 创建 Pattern 对象
Pattern r = Pattern.compile(pattern);
// 现在创建 matcher 对象
Matcher m = r.matcher(line);

正则表达式语法可以查看:菜鸟教程/正则表达式/正则表达式语法

成员变量

成员变量是定义在类内部、方法外部的变量

方法

方法重载 (Overloading)

核心概念
同一个类中,允许存在多个同名方法,但要求它们的参数列表不同(类型、数量或顺序不同)。

规则

  1. 方法名必须相同
  2. 参数列表必须不同(以下至少满足一项):
    • 参数类型不同
    • 参数数量不同
    • 参数顺序不同
  3. 与返回值类型无关(返回值可相同也可不同)

可变参数 (Varargs)

核心概念
允许方法接受任意数量的同类型参数(本质是数组的语法糖)。

语法
在参数类型后加 ...
void methodName(Type... varName)

规则

  1. 一个方法只能有一个可变参数
  2. 必须是方法的最后一个参数
  3. 可以接受 0 到多个参数

构造方法

用来创建类的实例对象的方法。
特点 :

  1. 与类名相同;
  2. 没有返回类型;
  3. 默认构造方法,在没有定义任何构造方法的时候,java会自动提供一个无参构造方法;
  4. this关键字使用,在调用其他构造方法时,必须放在构造方法的第一行;
  5. 不能被继承,但是可以被调用,子类使用 super();

代码块

静态代码块

声明方式:static{}
特点:类加载的时候优先执行(比 mian 方法快),只执行一次;一般用于初始化。

实例代码块

声明方式:{}
特点:类每次实例化的时候执行一次,多个实例代码块按顺序执行;初始化对象的实例资源。

内部类

在类A里面定义一个类B,这个类B就是内部类。

成员内部类

声明如下:

1
2
3
4
public class Outer{
public class Inner{
}
}

调用:new Outer().new Inner()
特点:

  • 内部类可以直接访问外部类的成员变量和方法
  • 内部类看直接拿到外部类的对象,如:Outer.this

静态内部类

声明如下:

1
2
3
public class Outer{
public static class Inner{}
}

调用:new Outer().Inner()

静态内部类不能直接访问外部实例成员,

匿名内部类

定义:new className{类体,一般为方法},className 可以是接口和类
如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public abstract class Animal{
public abstract void cry();
}

public class Test{
//成员内部类
class Cat extends Animal{
@Override
public void cry(){}
}

// 匿名内部类,Animal 也可以是接口
new Animal(){
@Override
public void cry(){/* 重写方法 */}
}
}

特点:

  • 编译之后,会出现 类名字$+阿拉伯数字 的class文件,其实就是匿名内部类;如:Test$1.class
  • 使用更加方便

常见形式

  1. 作为一个对象参数传送给方法。
1
2
3
4
5
6
7
8
9
10
11
12
13
public void start(Animal an){
an.cry();
}
// start 方法可以按照多态调用,如:Animal an = new Cat();
// 使用匿名内部类的方式,则如下:
Animal an = new Animal(){
@Override
public void cry(){}
};
start(an);// an 可以把等号右边的直接带进来。

// 匿名内部类可以进一步简化,这里用的式 lambda 表达式
start(an -> System.out.println(1))
  1. 某些方法会需要手动传入 匿名内部类的参数,如:
1
2
3
4
5
6
7
JButton btn = new JButton("login");
btn.addActionListener(new ActionListener(){
@Override
public void actionPerformed(ActionEvent e){
//……
}
})

异常处理

主要分为三种异常:

  1. 检查性异常,可以使用try-catch或者throws来处理。
1
2
3
4
5
6
7
8
9
10
11
try (resource declaration) {
// 使用的资源
} catch (ExceptionType e1) {
// 异常块
}finally{

}
// ===========or========
public void readFile() throws IOException {
// 可能会抛出IOException的代码
}
  1. 运行时异常,最常见的就是 NullPointerException

  2. 错误:不是异常,容易忽略的地方,比如栈溢出。

throw 用于手动抛异常,如:

1
2
3
4
5
 public void checkNumber(int num) {
if (num < 0) {
throw new IllegalArgumentException("Number must be positive");
}
}

自定义异常

  1. 自定义编译时异常
  • 继承 Exception
  • 重写 Exception 的构造器,一般 super(message) 就足够了,message是参数
  1. 自定义运行时异常
  • 继承 RuntimeException
  • 重写 RuntimeException 的构造器,同上

异常处理方案

  1. 最底层抛到最外层
  2. 最外层捕获(try-catch)异常后,尝试重新修复。

字符集

  1. 标准 ACSII 码,美国信息交换编码,一个字节(首位是0)存储一个字符,只包括了英文、符号;总工128个。
  2. GBK,汉字编码字符集,一个中文字符两个字节(首位是1),包括两万多个字符。且兼容了 ACSII 字符集。
  3. Unicode字符集(统一码,也叫万国码),是国际组织制定的,可以容纳世界上所有文字、符号的字符集;
  • Unicode-32(2^32个字符),四个字节一个字符,存储空间占用大,少用使用
  • Unicode-8,现在快全球统一的编码,英文字符、数字等只占1个字节(兼容标准ASCII编码),汉字字符占用3个字节(首位111);其他还有2字节(首位11)和4字节(首位1111)的

编码和解码必须使用统一字符集
数字和英文一般不会乱码,因为很多字符集都兼容了ASCII码。

编码和解码

  1. 对字符的编码,String提供了如下方法

    方法签名 说明
    :— :—
    byte[] getBytes() 使用平台的默认字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中
    byte[] getBytes(String charsetName) 使用指定的字符集将该 String 编码为一系列字节,将结果存储到新的字节数组中
  2. 对字符的解码,String提供了如下构造方法

    构造方法 说明
    :— :—
    String(byte[] bytes) 通过使用平台的默认字符集解码指定的字节数组来构造新的 String
    String(byte[] bytes, String charsetName) 通过指定的字符集解码指定的字节数组来构造新的 String

常用类

Number

Number 是除开 boolean 和 Character 之外的所有基本数字类型的包装类的抽象父类,提供各种数值类型的转换。

主要子类:

1
2
Integer num1 = Integer.valueOf("100");
Double num2 = Double.parseDouble("3.14");
  1. 基本类型转换
1
2
3
4
5
6
Number num = 1234.56; // 实际是Double类型

System.out.println(num.intValue()); // 1234 (截断小数)
System.out.println(num.longValue()); // 1234
System.out.println(num.floatValue()); // 1234.56
System.out.println(num.doubleValue()); // 1234.56
  1. 数值比较
1
2
3
4
5
Integer x = 10;
Double y = 10.0;

// 正确比较方式:转换为同一类型后比较
System.out.println(x.doubleValue() == y.doubleValue()); // true
  1. 处理大数
1
2
3
4
5
6
BigInteger bigInt = new BigInteger("12345678901234567890");
BigDecimal bigDec = new BigDecimal("1234567890.1234567890");

// 大数运算
BigInteger sum = bigInt.add(new BigInteger("1"));
BigDecimal product = bigDec.multiply(new BigDecimal("2"));
  1. 数值格式化
1
2
3
4
NumberFormat nf = NumberFormat.getInstance();
nf.setMaximumFractionDigits(2);

System.out.println(nf.format(1234.5678)); // "1,234.57"
  1. 装箱和拆箱
1
2
3
4
5
6
7
8
9
10
11
// 自动装箱 (Auto Boxing)
Integer autoBoxed = 10; // 基本类型 int → 包装类 Integer

// 手动装箱 (Manual Boxing)
Integer manualBoxed = Integer.valueOf(10); // 使用 valueOf 方法

// 自动拆箱 (Auto Unboxing)
int autoUnboxed = autoBoxed; // 包装类 Integer → 基本类型 int

// 手动拆箱 (Manual Unboxing)
int manualUnboxed = manualBoxed.intValue(); // 使用 xxxValue 方法

Math

常用的数学函数、公式和特征值。

1
2
3
4
// 生成[0.0, 1.0)之间的随机数
double random = Math.random();
// 生成[1, 100]的随机整数
int randomInt = (int)(Math.random() * 100) + 1;

Character

Character 类用于对单个字符进行操作。

Character 类在对象中包装一个基本类型 char 的值,用于处理需要对象,而不是内置数据的情况。
示例:

1
2
3
4
5
6
7
8
9
10
char ch = 'a';

// Unicode 字符表示形式
char uniChar = '\u039A';

// 字符数组
char[] charArray ={ 'a', 'b', 'c', 'd', 'e' };

// 对象
Character ch = new Character('a');

String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//声明方式
String str = "hello world";
String str2=new String("hello world");
String str3 = new String(byte数组,偏移量,数组长度);
//连接字符串
str.concat(str2);

//创建格式化字符串
System.out.printf("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
" %s", floatVar, intVar, stringVar);

String fs;
fs = String.format("浮点型变量的值为 " +
"%f, 整型变量的值为 " +
" %d, 字符串变量的值为 " +
" %s", floatVar, intVar, stringVar);

StringBuffer

对字符串修改时候会用到,与 String 不同的是,这两个被多次修改也不会产生新的对象。
StringBuilder 线程不安全速度快,多线程使用 StringBuffer

特性 String StringBuffer StringBuilder
可变性 ✔️ ✔️
线程安全 ✔️
性能

Scanner

获取用户的输入:

1
2
3
4
5
6
7
8
9
10
11
Scanner s = new Scanner(System.in);
// 从键盘接收数据

// next方式接收字符串
System.out.println("next方式接收:");
// 判断是否还有输入
if (scan.hasNext()) {
String str1 = scan.next();
System.out.println("输入的数据为:" + str1);
}
scan.close();

其他不过多记录,用得少

Stream、File、IO

字节流

字节流用于处理二进制数据,例如文件、图像、视频等。

类名 类型 描述
InputStream 抽象类(输入流) 所有字节输入流的超类,处理字节的输入操作。
OutputStream 抽象类(输出流) 所有字节输出流的超类,处理字节的输出操作。
FileInputStream 输入流 从文件中读取字节数据。
FileOutputStream 输出流 将字节数据写入文件。
BufferedInputStream 输入流 为字节输入流提供缓冲功能,提高读取效率。
BufferedOutputStream 输出流 为字节输出流提供缓冲功能,提高写入效率。
ByteArrayInputStream 输入流 将内存中的字节数组作为输入源。
ByteArrayOutputStream 输出流 将数据写入到内存中的字节数组。
DataInputStream 输入流 允许从输入流中读取 Java 原生数据类型(如 int, float, boolean)。
DataOutputStream 输出流 允许向输出流中写入 Java 原生数据类型。
ObjectInputStream 输入流 从输入流中读取序列化对象。
ObjectOutputStream 输出流 将对象序列化并写入输出流中。
PipedInputStream 输入流 用于在管道中读取字节数据,通常与 PipedOutputStream 配合使用。
PipedOutputStream 输出流 用于在管道中写入字节数据,通常与 PipedInputStream 配合使用。
FilterInputStream 输入流 字节输入流的包装类,用于对其他输入流进行过滤处理。
FilterOutputStream 输出流 字节输出流的包装类,用于对其他输出流进行过滤处理。
SequenceInputStream 输入流 将多个输入流串联为一个输入流进行处理。

字符流

字符流用于处理文本数据,例如读取和写入字符串或文件。

类名 类型 描述
Reader 抽象类 (输入流) 所有字符输入流的超类,处理字符的输入操作。
Writer 抽象类 (输出流) 所有字符输出流的超类,处理字符的输出操作。
FileReader 输入流 从文件中读取字符数据。父类是 InputStreamReader
FileWriter 输出流 将字符数据写入文件。父类是 OutputStreamWriter
BufferedReader 输入流 为字符输入流提供缓冲功能,支持按行读取,提高读取效率。
BufferedWriter 输出流 为字符输出流提供缓冲功能,支持按行写入,提高写入效率。
CharArrayReader 输入流 将字符数组作为输入源。
CharArrayWriter 输出流 将数据写入到字符数组。
StringReader 输入流 将字符串作为输入源。
StringWriter 输出流 将数据写入到字符串缓冲区。
PrintWriter 输出流 便捷的字符输出流,支持自动刷新和格式化输出。
PipedReader 输入流 用于在管道中读取字符数据,通常与PipedWriter配合使用。
PipedWriter 输出流 用于在管道中写入字符数据,通常与PipedReader配合使用。
LineNumberReader 输入流 带行号的缓冲字符输入流,允许跟踪读取的行号。
PushbackReader 输入流 允许在读取字符后将字符推回流中,以便再次读取。
PrintStream 输出流 将各种数据格式化为字符文本并输出,System.out 就是一个 PrintStream 对象

辅助类(File类等)

辅助类提供对文件、目录以及随机文件访问的支持。

姓名 类型 描述
File 文件和目录操作 用于表示文件或目录,并提供文件操作,如创建、删除、重命名等。 不能读写里面存储的数据
RandomAccessFile 随机访问文件 支持文件的随机访问,可以从文件的任意位置读写数据。
Console 控制台输入输出 提供对系统控制台的输入和输出支持。

File特点:

  • new File(“a.txt”),文件不存在时会自动创建
  • file.delete(),文件夹为空才能删。

基本例子

字节流
  1. FileInputStream,输入流对象来读取文件
1
2
3
4
InputStream f = new FileInputStream("C:/java/hello");
//或者
File f = new File("C:/java/hello");
InputStream in = new FileInputStream(f);
  1. FileOutputStream,该类用来创建一个文件并向文件中写数据。
1
2
3
4
OutputStream f = new FileOutputStream("C:/java/hello")
//或者
File f = new File("C:/java/hello");
OutputStream os = new FileOutputStream(f,true);//第二个参数是是否追加写入

流用完记得关,eg:os.close();

  1. 字节流复制
    JDK1.7 开始,Java提供了Files用于简化IO操作,气质的copy(Path src,Path des)方法,可以复制。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public static void copyFile(String srcPath,String desPath){
//JDK7开始(父类流实现了 AutoCloseable),在try括号里面,会自动关闭,不用手动关闭。
try(InputStream fis = new FileInputStream(srcPath);
OutputStream fos = new FileOutputStream(desPath)){
byte[] buffer = new byte[1024];
int len;
while(len = fis.read(buffer) != -1){
fos.write(buffer,0,len);
}
System.out.println("复制成功");
}catch (IOException e){
e.printStackTrace();
}
}
字符流
  1. 输入流
1
2
3
4
5
6
7
8
9
try(Reader fr = new FileReader("D:/a.txt")){
char[] chs = new char[1024];
int len;
while(len = fr.read(chs) != -1){
String str = new String(chs,0,len);
}catch(IOException e){
e.printStackTrace();
}
}
  1. 输出流
1
2
3
4
5
6
try(Writer fw = new FileWriter("D:/a.txt"true)){//true 是内容追加
fw.write("XXX");
fw.flush(); //刷新写入的内容生效,流可以继续使用。
}catch(IOException e){
e.printStackTrance();
}

字符输出流写出数据后必须刷新流或者关闭流,写出去的数据才能生效。

指定编码IO

解决不同编码时,字符流读取文本内容乱码的问题。
解决思路:先获取文件的原始字节流,再将其按真实的字符集编码转成字符输入流,这样字符输入流中的字符就不乱码了,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
File f = new File("a.txt");
// 构建FileOutputStream对象,文件不存在会自动新建
FileOutputStream fop = new FileOutputStream(f);//原始字节流
// 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk
OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
// 写入到缓冲区
writer.append("中文输入");
// 换行
writer.append("\r\n");
// 刷新缓存冲,写入到文件,如果下面已经没有写入的内容了,直接close也会写入
writer.append("English");
// 关闭写入流,同时会把缓冲区内容写入文件,所以上面的注释掉
writer.close();
// 关闭输出流,释放系统资源
fop.close();

// 构建FileInputStream对象
FileInputStream fip = new FileInputStream(f);
// 构建InputStreamReader对象,编码与写入相同
InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
StringBuffer sb = new StringBuffer();
while (reader.ready()) {
// 转成char加到StringBuffer对象中
sb.append((char) reader.read());
}
System.out.println(sb.toString());
// 关闭读取流
reader.close();
// 关闭输入流,释放系统资源
fip.close();

缓冲流buffer

管道概率:在 Java I/O 中,管道是一种用于在不同线程之间进行数据通信的特殊流。它提供了一种让一个线程发送数据而另一个线程接收数据的机制,类似于实际生活中的管道概念。
作用:用于提高性能。低级管道决定特性,高级管道决定性能
原理:缓冲字节输入流自带了8KB缓冲池;缓冲字节输出流也自带了8KB(桶大小)缓冲池

  1. BufferInputStream
    直接将InputStream作为构造参数new一个BufferInputStream,其他一样。
  2. BufferedReader,同上。不同的是有个有 readLine()方法,按行读。

    作为子类的bufferxxx,有些自己定义的方法,实际使用的时候自行选择。

日期时间相关类

Date

(已过时,建议使用 java.time 包)

基本使用
1
2
Date now = new Date(); // 当前时间
long time = now.getTime(); // 时间戳

SimpleDateFormat

日期格式化类
(可以使用 java.time 中的 DateTimeFormatter 替代)

使用示例
1
2
3
4
5
6
7
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

// 日期转字符串
String str = sdf.format(new Date());

// 字符串转日期
Date date = sdf.parse("2023-01-01 12:00:00");
注意事项
  • 非线程安全,多线程环境需配合 ThreadLocal 使用
  • 格式符号:yyyy-年,MM-月,dd-日,HH-小时(24h 制)

Calendar

日期操作类

常用方法
1
2
3
4
5
6
7
8
9
10
Calendar cal = Calendar.getInstance();

// 获取字段
int year = cal.get(Calendar.YEAR);

// 设置时间
cal.set(2023, Calendar.JANUARY, 1);

// 日期计算
cal.add(Calendar.DAY_OF_MONTH, 5); // 加5天
注意事项
  • 月份从 0 开始(0=January)
  • 推荐使用 Calendar.getInstance() 获取实例

java.time

参考:https://javaguidepro.com/blog/datetime-java/

基本使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
// 获取当前日期
LocalDate currentDate = LocalDate.now();
// 创建指定日期
LocalDate specificDate = LocalDate.of(2024, 1, 1);
// 获取当前时间
LocalTime currentTime = LocalTime.now();
// 创建指定时间
LocalTime specificTime = LocalTime.of(12, 30, 0);
// 获取当前日期时间
LocalDateTime currentDateTime = LocalDateTime.now();
// 创建指定日期时间
LocalDateTime specificDateTime = LocalDateTime.of(2024, 1, 1, 12, 30, 0);
// 获取当前带时区的日期时间
ZonedDateTime currentZonedDateTime = ZonedDateTime.now();

// 指定时区创建日期时间
ZoneId zoneId = ZoneId.of("Asia/Shanghai");
ZonedDateTime specificZonedDateTime = ZonedDateTime.of(2024, 1, 1, 12, 30, 0, 0, zoneId);

// 定义格式化模式
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// 格式化日期时间
LocalDateTime dateTime = LocalDateTime.now();
String formattedDateTime = dateTime.format(formatter);

// 比较日期
LocalDate startDate = LocalDate.of(2024, 1, 1);
LocalDate endDate = LocalDate.of(2024, 12, 31);
boolean isBefore = startDate.isBefore(endDate);

// 计算日期差值
Period period = Period.between(startDate, endDate);
System.out.println("两个日期之间的差值: " + period.getYears() + " 年 " + period.getMonths() + " 月 " + period.getDays() + " 天");
String dateStr = "2024-01-01";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");

// 解析日期字符串
LocalDate parsedDate = LocalDate.parse(dateStr, formatter);
System.out.println("解析后的日期: " + parsedDate);

// 指定一个日期(例如:2023-10-01)
LocalDate specifiedDate = LocalDate.of(2023, 10, 1);
// 获取该日期后5天的日期
LocalDate resultDate = specifiedDate.plusDays(5);

参考