API

API(Application Programming Interface):应用程序编程接口。就是别人写好的一些类,给程序员直接拿去调用即可

解决问题

Java中的API有很多,这些API不用去死记硬背,需要使用的时候查询API文档即可

在线地址(JDK11汉化版本):https://www.runoob.com/manual/jdk11api/index.html

官方API地址(无汉化,全版本):https://docs.oracle.com/en/java/javase/21/docs/api/index.html

当查询API文档还是没弄清如何使用,直接在搜索引擎中查询也能解决问题

String类

特点:

  1. Java程序中所有字符串文字(例如”abc”)都是String类的对象

  2. String是不可改变的,它们的值在创建后无法更改。想要更改,需要使用新的对象替换

    1
    2
    String s = "abc";
    s = "cba"; // 替换新对象
  3. String虽然不可改变,但是可以被共享操作

    1
    2
    3
    String s1 = "abc";
    String s2 = "abc";
    System.out.println(s1 == s2); // true

    字符串常量池(String Pool):当使用双引号创建字符串对象的时候,会检查数据在常量池中是否存在

    如果不存在:创建新的对象,如果存在:复用对象

String构造方法

  • public String():创建空白字符串,不含有任何内容
  • public String(char[] chs):根据字符数组,创建字符串对象
  • public String(String original):根据传入的字符串创建字符串对象

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class StringDemo01 {
public static void main(String[] args) {
String s1 = new String();
System.out.println(s1);

char[] chs = {'a','b','c'};
String s2 = new String(chs);
System.out.println(s2); // abc

String s3 = new String("abc");
System.out.println(s3); // abc

System.out.println(s2 == s3); // false
}
}

双引号创建字符串对象:数据在字符串常量池中存储

构造方法创建:会在堆内存中开辟独立的内存空间

String类面试题

利用构造方法创建String对象

字符串面试题1

String s2 = new String(“abc”);实际上创建了两个对象

一个对象存放在StringTable中,另一个对象直接开辟在堆内存中

然后将StringTable中字符串对象的地址值复制给了堆内存中字符串对象(因为字符串底层是字符数组,数组给数组赋值就是复制地址值)

变量与字面量拼接

1
2
3
4
String s1 = "abc";
String s2 = "ab";
String s3 = s2 + "c";
System.out.println(s1 == s3); // false

字符串串联是通过StringBuilder(或StringBuffer)类及其append方法实现的
也是说当出现字符串拼接时,底层会创建StringBuilder类并调用append方法重新创建一个字符串对象,然后再通过toString又创建出最终的字符串对象

底层代码:new StringBuilder().append(s2).append("c").toString();

toString():创建新 String 对象(内容为 “abc”),但不在常量池中

字符串面试题2

字面量与字面量拼接

1
2
3
String s1 = "abc";
String s2 = "a" + "b" + "c";
System.out.println(s1 == s2); // true

这里的结果为true是因为s2的操作是字面量拼接,而上个案例是变量与字面量拼接

Java对于字面量拼接是有优化的,所以在字节码文件中显示的就是String s2 = "abc"

String类比较

  • public boolean equals(要比较的字符串):完全一样结果为True,否则为False

示例:

1
2
3
4
5
6
7
8
9
10
String s1 ="abc";
String s2 = new String("abc");
System.out.println(s1.equals(s2)); // true

String tmp = "c";
String s3 = "ab" + tmp;
System.out.println(s3.equals(s1)); // true

String s4 = "a" + "b" + "c";
System.out.println(s4.equals(s1)); // true
  • public boolean equalsIgnoreCase(要比较的字符串):忽略大小写的比较

示例:

1
2
3
String s1 = "Hello World";
String s2 = new String("hello world");
System.out.println(s1.equalsIgnoreCase(s2)); // true

String字符串遍历

  • public char[] toCharArray():将字符串转换为字符数组

示例:

1
2
3
4
5
6
String s1 = "Hello World";
char[] chs = s1.toCharArray();

for (int i = 0; i < chs.length; i++) {
System.out.print(chs[i]);
}
  • public char charAt(int index):根据索引查找字符

示例:

1
2
3
4
String s1 = new String("Hello World");
char c = s1.charAt(0);

System.out.println(c); // H
  • public int length():返回字符串的长度,注意不能省略括号

示例:

1
2
String s1 = "Hello World";
System.out.println(s1.length()); // 11

案例:获取某个字符串中大写字母、小写字母、数字的个数

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
import java.util.Scanner;

public class StringDemo08 {
public static void main(String[] args) {
// 例如:aAb3&c2B*4CD1

Scanner sc = new Scanner(System.in);
System.out.print("请输入:");
String content = sc.next();

char[] chs = content.toCharArray();

int UpperLetter = 0;
int LowerLetter = 0;
int NumberLetter = 0;

for (int i = 0; i < chs.length; i++) {
if (chs[i] >= 'a' && chs[i] <= 'z') {
LowerLetter++;
} else if (chs[i] >= 'A' && chs[i] <= 'Z') {
UpperLetter++;
} else if (chs[i] >= '0' && chs[i] <= '9') {
NumberLetter++;
}
}

System.out.println("大写字母个数:" + UpperLetter);
System.out.println("小写字母个数:" + LowerLetter);
System.out.println("数字个数:" + NumberLetter);
}
}

字符串截取

  • public String substring(int beginIndex);:从开始索引截取到末尾
  • public String substring(int beginIndex, int endIndex);:根据索引范围截取字符串,包头不包尾

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
String s1 = "Hello World";
int begin = 0;
int end = 0;
for (int i = 0; i < s1.length(); i++) {
if (s1.charAt(i) == 'W') {
begin = i;
}
if (s1.charAt(i) == 'd') {
end = i;
}
}
System.out.println(s1.substring(begin)); // World
System.out.println(s1.substring(begin, end + 1)); // World

案例:将手机号中间4位数用*号替代

1
2
3
4
5
6
7
8
Scanner sc = new Scanner(System.in);
System.out.print("请输入手机号:");
String phone = sc.next();

String begin = phone.substring(0,3);
String end = phone.substring(7);

System.out.println(begin + "****" + end);

字符串替换方法

  • public String replace(旧值, 新值):替换,返回值为替换结果

示例:

1
2
3
4
5
6
7
// 将敏感词替换为***
Scanner sc = new Scanner(System.in);
System.out.println("请输入:");
String s = sc.next();

s = s.replace("TMD","***");
System.out.println(s);

字符串切割

  • public String[] split(String regex);:根据传入的字符串作为规则进行切割,将切割后的内容存入字符串数组中,并将字符串数组返回

示例:

1
2
3
4
5
6
String ip = "192.168.100.200";
String[] split = ip.split("\\."); // 以 . 为分隔规则

for (String s : split) {
System.out.println(s);
}

String常用方法总结

方法 说明
public boolean equals(String s); 字符串与字符串比较,完全一致返回true,否则返回false
public boolean equalsIgnoreCase(String s); 字符串与字符串比较,忽略大小写
public char[] toCharArray(); 将字符串转换为字符数组
public char charAt(int index); 根据索引找字符
public int length(); 返回字符串长度
public String substring(int beginIndex); 从开始索引截取到字符串末尾
public String substring(int beginIndex, int endIndex); 从开始索引截取到末尾所以,包头不包尾
public String replace(“oldString”, “newString”); 将字符串中旧的值替换为新的值
public String[] split(String regex); 根据规则切割字符串,返回切割后的字符串数组

StringBuilder

  • 提高字符串的操作效率
  • StringBuilder是字符串缓冲区,可以将其理解为是一种容器
    • 容器可以添加任意数据类型,但是只要进入这个容器,全部变成字符串
  • StringBuilder是一个可变的字符序列

普通String类和StringBuilder对比:

1
2
3
4
5
6
7
8
9
10
11
12
// 普通String类
// System.currentTimeMillis();记录了1970年1月1日到现在所经历的毫秒值
long before = System.currentTimeMillis(); // 开始时间

String s = "";
for (int i = 0; i < 100000; i++) {
s += i;
}

long after = System.currentTimeMillis(); // 结束时间
System.out.println(s);
System.out.println("花费时长:" + (after - before)); // 4685毫秒
1
2
3
4
5
6
7
8
9
10
11
// StringBuilder类
StringBuilder sb = new StringBuilder();
long before = System.currentTimeMillis();

for (int i = 0; i < 100000; i++) {
sb.append(i);
}

long after = System.currentTimeMillis();
System.out.println(sb);
System.out.println("花费时长:" + (after - before)); // 5毫秒

StringBuilder方法

StringBuilder构造方法

构造器 说明
StringBuilder() 构造一个字符串构建器,其中不包含任何字符,初始容量为16字符
StringBuilder(int capacity) 构造一个字符串构建器,其中没有任何字符,并且具有capacity参数指定的初始容量
StringBuilder(CharSequence seq) 构造一个字符串构建器,其中包含于指定CharSequence相同的字符
StringBuilder(String str) 构造一个初始化为指定字符串内容的字符串构建器

append添加方法

  • public StringBuilder append(任意类型);:添加数据到缓冲区,返回对象自己

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
StringBuilder sb = new StringBuilder();
StringBuilder sb1 = sb.append("红色");
StringBuilder sb2 = sb.append("绿色");
StringBuilder sb3 = sb.append("蓝色");

System.out.println(sb == sb1); // true
System.out.println(sb1 == sb2); // true
System.out.println(sb2 == sb3); // true

System.out.println(sb); // 红色绿色蓝色
System.out.println(sb1); // 红色绿色蓝色
System.out.println(sb2); // 红色绿色蓝色
System.out.println(sb3); // 红色绿色蓝色

// 以上代码可以通过链式编程优化:
StringBuilder sb = new StringBuilder();
sb.append("红色").append("绿色").append("蓝色"); // 红色绿色蓝色

System.out.println(sb);

链式编程:如果方法返回值是对象,就可以继续向下调用方法

reverse反转方法

  • public StringBuilder reverse();:反转缓冲区的内容

示例:

1
2
3
4
StringBuilder sb = new StringBuilder("1234");
sb.reverse().append("1234").reverse(); // 1234 => 4321 => 43211234 => 43211234

System.out.println(sb); // 43211234

length获取长度方法

  • public int length();:获取长度

示例:

1
2
3
4
5
StringBuilder sb = new StringBuilder();
sb.append("1234567890");

System.out.println(sb.length()); // 10
System.out.println(sb.capacity()); // 16

toString转换类型方法

  • public String toString();:转换为String类型

示例:

1
2
3
4
5
6
7
8
9
10
11
StringBuilder sb = new StringBuilder();
sb.append("1234567890");

if (sb instanceof StringBuilder) {
System.out.println("我是StringBuilder类型");
}

String string = sb.toString();
if (string instanceof String) {
System.out.println("我是String类型");
}

案例——回文字符串

需求:键盘接收一个字符串,程序判断出该字符串是否是回文字符串,并在控制台打印是或不是

回文字符串:123321,111

非回文字符串:123123

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
import java.util.Scanner;

public class StringBuilderTest01 {
/*
需求:键盘接收一个字符串,程序判断出该字符串是否是回文字符串,并在控制台打印是或不是
回文字符串:123321,111
非回文字符串:123123
*/

public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.print("请输入:");
String input = sc.next();

StringBuilder sb = new StringBuilder(input);

if (input.equals(sb.reverse().toString())) {
System.out.println("是");
} else {
System.out.println("不是");
}
}
}

案例——拼接字符串

需求:定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回

调用该方法,并在控制台输出结果

例如:数组int[] arr = {1, 2, 3};

执行方法后的输出结果为:[1,2,3]

代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
public class StringBuilderTest02 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5,6,7,8,9};
String formatArr = printArr(arr);
System.out.println(formatArr);
}

public static String printArr(int[] arr) {
StringBuilder sb = new StringBuilder();
sb.append("[");
for (int i = 0; i < arr.length; i++) {
if (i != arr.length - 1) {
sb.append(i).append(",").append(" ");
} else {
sb.append(i);
}
}
sb.append("]");

return sb.toString();
}
}

StringBuilder原理

字符串拼接底层实现:

字符串拼接底层原理

当直接使用String类进行字符串拼接时,底层会创建新的StringBuilder对象,拼接一次就创建一个新的对象,这会浪费性能

但是通过StringBuilder调用append方法,等到所有拼接操作完成后再利用toString()转换为String类型,这个过程只会创建一次StringBuilder对象

StringBuffer

在官方文档,对StringBuilder的描述是这样的:

  • 一个可变的字符序列。 此类提供与StringBuffer兼容的API但不保证同步。 此类设计用作StringBuffer替代品,用于单个线程使用字符串缓冲区的位置(通常情况下)。

对StringBuffer的描述是这样的:

  • 线程安全,可变的字符序列。 字符串缓冲区类似于String ,但可以进行修改。 在任何时间点它都包含一些特定的字符序列,但序列的长度和内容可以通过某些方法调用来改变。

总结来说:StringBuilder是兼容StringBuffer的。当只有单个线程时,可以使用StringBuilder,因为StringBuilder的性能更好。StringBuffer虽然性能不如StringBuilder,但是适用于涉及线程安全的情况。

Math类

  • 包含执行基本数字运算的方法
方法名 说明
public static int abs(int a) 获取参数绝对值
public static double ceil(double a) 向上取整
public static double floor(double a) 向下取整
public static int round(double a) 四舍五入
public static int max(int a,int b) 获取两个int值中的较大值
public static double pow(double a,double b) 返回a的b次幂的值
public static double random() 返回值为double的随机值,范围[0.0, 1.0)

示例:

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
public class MathDemo01 {
/*
| 方法名 | 说明 |
| ------------------------------------------- | -------------------------------------- |
| public static int abs(int a) | 获取参数绝对值 |
| public static double ceil(double a) | 向上取整 |
| public static double floor(double a) | 向下取整 |
| public static int round(double a) | 四舍五入 |
| public static int max(int a,int b) | 获取两个int值中的较大值 |
| public static double pow(double a,double b) | 返回a的b次幂的值 |
| public static double random() | 返回值为double的随机值,范围[0.0, 1.0] |
*/
public static void main(String[] args) {
int num01 = -123;
int num02 = 123;
System.out.println(Math.abs(num01) == Math.abs(num02)); // 100

double d1 = 3.1314;
System.out.println(Math.ceil(d1) + Math.floor(d1) + Math.round(d1)); // 10.0 = 3.0 + 4.0 + 3.0

System.out.println(Math.max(99,100)); // 100

System.out.println(Math.pow(2,8)); // 256.0

System.out.println(Math.random()); // 0 ~ 无限接近于1

}
}

System类

  • 和系统相关的操作
方法名 说明
public static void exit(int status) 终止当前运行的Java虚拟机,非零表示异常终止
public static long currentTimeMillies() 返回当前系统的时间毫秒值(当前时间 - 1970/1/1)
public static void arraycopy(Object src,int srcPos,Object dest,int destPos,int length) 数组拷贝
1. 数组源数据
2. 起始索引
3. 目的地数组
4. 起始索引
5. 拷贝的个数

System类中的方法都接近于底层操作,性能较好

包装类

  • 将基本数据类型,包装成类(变成引用数据类型)
  • 当基本数据类型包装成了类,也就可以创建对象,对象中的方法可以解决一些特定问题
基本数据类型 引用数据类型
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean

Integer类

  • 将基本数据类型,手动包装为类
  • 两种方式:
    • public Integer(int value); // 构造方法创建对象,新版本已经弃用,且未来可能被移除
    • public static Integer valueOf(int i); // 静态方法返回对象

示例:

1
2
int i = 10;
Integer integer = Integer.valueOf(i);

以上这种方式,为手动装箱。将基本数据类型,手动包装为类

1
2
3
int i1 = 10;
Integer integer = Integer.valueOf(i1);
int i2 = integer.intValue();

以上这种方式,为手动拆箱。将包装类对象,转换为基本数据类型

自动拆装箱(JDK5版本之后):

1
2
3
4
5
6
7
Integer integer = 10;
int i = integer;
System.out.println(i); // 10

Integer integer1 = 11;
int i1 = 12;
System.out.println(integer1 + i1); // 23

常见方法

方法名 说明
public static String toBinaryString(int i) 得到二进制
public static String toOctalString(int i) 得到八进制
public static String toHexString(int i) 得到十六进制
public static int parseInt(String s) 把字符串类型的整数转成int类型的整数

除了Character,所有包装类都有parseXXX()的方法,都是用于转换成自己对应的基本数据类型

BigDecimal类

  • 用于解决小数运算中,出现的不精确问题

比如:

1
2
3
double d1 = 0.1;
double d2 = 0.2;
System.out.println(d1 + d2); // 0.30000000000000004
  • 创建对象方法
    • public BigDecimal(double val); // 不推荐,创建出的对象依旧存在不精确问题
    • public BigDecimal(String val);
    • public static BigDecimal valueOf(double val);

示例:

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
package bigDecimal;

import java.math.BigDecimal;

public class BigDecimalDemo02 {

public static void main(String[] args) {
// 创建对象方法
//- public BigDecimal(double val); // 不推荐,创建出的对象依旧存在不精确问题
//- public BigDecimal(String val);
//- public static BigDecimal valueOf(double val);

BigDecimal bigDecimal_01 = new BigDecimal(0.1);
BigDecimal bigDecimal_02 = new BigDecimal(0.2);
System.out.println(bigDecimal_01.add(bigDecimal_02)); // 0.3000000000000000166533453693773481063544750213623046875

bigDecimal_01 = new BigDecimal("0.1");
bigDecimal_02 = new BigDecimal("0.2");

System.out.println(bigDecimal_01.add(bigDecimal_02)); // 0.3

bigDecimal_01 = BigDecimal.valueOf(0.1 );
bigDecimal_02 = BigDecimal.valueOf(0.2);
System.out.println(bigDecimal_01.add(bigDecimal_02)); // 0.3
}
}

常见方法

方法名 说明
public BigDecimal add(BigDecimal b) 加法
public BigDecimal subtract(BigDecimal b) 减法
public BigDecimal multiply(BigDecimal b) 乘法
public BigDecimal divide(BigDecimal b) 除法
public BigDecimal divide(另一个BigDecimal对象,精确几位,舍入模式) 除法
public double doubleValue(BigDecimal b); 将BigDecimal转换为double类型

舍入模式:RoundingMode.Half_UP 四舍五入RoundingMode.UP 进一法RoundingMode.DOWN 去尾法

示例:

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
package bigDecimal;

import java.math.BigDecimal;
import java.math.RoundingMode;

public class BigDecimalDemo03 {
/*
| 方法名 | 说明 |
| ------------------------------------------------------------ | ---- |
| public BigDecimal add(BigDecimal b) | 加法 |
| public BigDecimal subtract(BigDecimal b) | 减法 |
| public BigDecimal multiply(BigDecimal b) | 乘法 |
| public BigDecimal divide(BigDecimal b) | 除法 |
| public BigDecimal divide(另一个BigDecimal对象,精确几位,舍入模式) | 除法 |
*/
public static void main(String[] args) {
BigDecimal bd1 = BigDecimal.valueOf(10.0);
BigDecimal bd2 = BigDecimal.valueOf(3.0);

double res1 = bd1.add(bd2).doubleValue();
double res2 = bd1.subtract(bd2).doubleValue();
double res3 = bd1.multiply(bd2).doubleValue();
System.out.println(res1);
System.out.println(res2);
System.out.println(res3);

// 当遇到除不尽的情况,就会出现异常
// double res4 = bd1.divide(bd2).doubleValue(); 10 / 3 除不尽
double res4 = bd1.divide(bd2,2, RoundingMode.HALF_UP).doubleValue();
System.out.println(res4);
}
}

Arrays类

  • 数组操作工具类,专门用于操作数组元素
方法名 说明
public static String toString(类型[] a) 将数组元素拼接为带有格式的字符串
public static boolean eqauls(类型[] a, 类型[] b) 比较两个数组内容是否相同
public static int binarySearch(int[] a,int key) 查找元素在数组中的索引(二分查找法)
public static void sort(类型[] a) 对数组进行默认升序排序
public static void sort(类型[] a, 比较器); 根据比较器进行排序

二分查找法:获取数组中间元素,如果中间元素小于查找值,说明在右边,如果中间元素大于查找值,说明在左边。然后再对左/右边的数组继续以上操作。直到中间元素 = 查找值

核心思想就是将数组一分为二,所以叫二分查找法。

当数组中不存在查找的元素,返回一个负数,且这个负数的值为查找元素如果存在,那它应该在的位置

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
package arrays;

import java.util.Arrays;
import java.util.Comparator;

public class ArraysDemo {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55,66,77,88,99};
System.out.println(Arrays.toString(arr)); // [11, 22, 33, 44, 55, 66, 77, 88, 99]

int[] arr1 = {11,22,33,44,55,66,77,88,99};
System.out.println(Arrays.equals(arr,arr1)); // true

System.out.println(Arrays.binarySearch(arr,77)); // 6


String[] arr2 = {"张三","李四","王五","张伞伞","李思思","王武武","Alice","Bob","Candy","David"};
Arrays.sort(arr2, Comparator.reverseOrder());
System.out.println(Arrays.toString(arr2)); // [王武武, 王五, 李思思, 李四, 张伞伞, 张三, David, Candy, Bob, Alice]
}
}

时间类

JDK8版本之前:Date、SimpleDateFormat

JDK8版本之后:LocalDate、LocalTime、LocalDateTime、DateTimeFormatter、ChronoUnit

JDK8版本之前

Date类

  • 代表的是日期和时间
构造器 说明
public Date() 创建一个Date对象,代表的是系统当前的日期时间
public Date(long time) 把时间毫秒值转换成Date日期对象

示例:

1
2
3
4
5
6
7
8
9
10
public class DateDemo01 {
public static void main(String[] args) {
Date d1 = new Date();
System.out.println(d1); // Wed Jul 30 16:57:10 CST 2020

Date d2 = new Date(0);
System.out.println(d2); // Thu Jan 01 08:00:00 CST 1970
}
}

常见方法

方法名 说明
public long getTime() 返回从1970年1月1日 00:00:00走到此前的总的毫秒数
public void setTime(long time) 设置日期对象的时间为当前时间毫秒值对应的时间

示例:

1
2
3
4
5
6
7
8
Date d1 = new Date();
Date d2 = new Date(5000);

System.out.println(d1.getTime()); // 1753866128367
System.out.println(d2.getTime()); // 5000

d2.setTime(10000);
System.out.println(d2.getTime()); // 10000

SimpleDateFormat类

  • 用于日期格式化
构造器 说明
public SimpleDateFormat() 构造一个SimpleDateFormat,使用默认格式
public SimpleDateFormat(String pattern) 构造一个SimpleDateForma,使用指定格式

格式化方法:

格式化方法 说明
public final format(Date date) 将日期格式化 日期/时间 字符串
public final Date parse(String source) 将字符串解析为日期类型

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class SimpleDateFormatDemo01 {
public static void main(String[] args) throws ParseException {
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年MM月dd HH:mm:ss");

Date now = new Date();
System.out.println(sdf1.format(now)); // 2020-07-30 17:09:53
System.out.println(sdf2.format(now)); // 2020年07月30 17:09:53

String myDate1 = "2000-01-01 00:00:00";
String myDate2 = "2000年01月01 00:00:00";
Date parse = sdf1.parse(myDate1);
System.out.println(parse);

parse = sdf2.parse(myDate2);
System.out.println(parse);
}
}

调用parse方法时,需要和格式化字符串匹配,否则会报错

计算年龄案例

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
package date.beforeJdk8;


import java.text.ParseException;
import java.text.SimpleDateFormat;

import java.util.Date;
import java.util.Scanner;

public class DateTest01 {
public static void main(String[] args) {
// 键盘录入用户的生日,计算出用户的年龄
Scanner sc = new Scanner(System.in);

System.out.println("请输入出生日期:");
String birthday= sc.next();

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

Date userBirthday = new Date();
Date today = new Date();
try {
userBirthday = sdf.parse(birthday);
} catch (ParseException e) {
System.out.println("输入日期格式错误!");
}

long l = today.getTime() - userBirthday.getTime();
long age = l / 1000 / 60 / 60 / 24 / 365;
System.out.println(age);
}
}

JDK8版本之后

新版本的时间API有以下优势:

  • 设计更合理,功能丰富,使用更方便
  • 都是不可变对象,修改后会返回新的时间对象,不会丢失最开始的时间
  • 线程安全
  • 能精确到毫米、纳秒

LocalDate:年、月、日

LocalTime:时、分、秒

LocalDateTime:年、月、日、时、分、秒

DateTimeFormatter:用于时间的格式化和解析

ChronoUnit:计算时间间隔的工具类

时间类

LocalDate:代表本地日期(年、月、日、星期)

LocalTime:代表本地时间(时、分、秒、纳秒)

LocalDateTime:代表本地日期、时间(年、月、日、星期、时、分、秒、纳秒)

获取对象

方法名 示例
public static Xxxx now():获取系统当前时间对应的该对象 LocalDate ld = LocalDate.now();
LocalTime lt = LocalTime.now();
LocalDateTime ldt = LocalDateTime.now();
public static Xxxx of(…):获取指定时间的对象 LocalDate ld = LocalDate.of(2009, 11, 11);
LocalTime lt = LocalTime.now(9, 8, 59);
LocalDateTime ldt = LocalDateTime.now(2025, 02, 16, 13, 35, 05);

示例:

1
2
3
4
5
6
7
8
9
10
LocalDateTime ldt = LocalDateTime.now();
System.out.println(ldt); // 2020-07-30T17:40:53.534061700

LocalDateTime setLDT = LocalDateTime.of(2007, 10,10,10,10,10,10);
System.out.println(setLDT); // 2007-10-10T10:10:10.000000010

LocalDate localDate = setLDT.toLocalDate();
LocalTime localTime = setLDT.toLocalTime();
System.out.println(localDate); // 2007-10-10
System.out.println(localTime); // 10:10:10.000000010

LocalDateTime是可以直接转换为LocalDate或LocalTime的

LocalDate和LocalTime经过组合也可以转换为LocalDateTime

获取具体时间

方法名 功能
int getYear() 获取年份字段
Month getMonth() 使用Month枚举获取年份字段
int getMonthValue() 获取1到12之间的月份字段
int getDayOfMonth() 获取日期字段
DayOfWeek getDayOfWeek() 获取星期几字段,即枚举DayOfWeek
int getHour() 获取当日时间字段
int getMinute() 获取分钟字段
int getSecond() 获取秒字段

示例:

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
// 获取具体的某天、某月、某日、某个星期
LocalDateTime localDateTime = LocalDateTime.of(2007,8,20,13,2
System.out.println(localDateTime); // 2007-08-20T13:27:50

// 年
int year = localDateTime.getYear();
// 月
Month month = localDateTime.getMonth();
int monthValue = month.getValue();
// 日
int dayOfMonth = localDateTime.getDayOfMonth();
// 星期
DayOfWeek dayOfWeek = localDateTime.getDayOfWeek();
int weekValue = dayOfWeek.getValue();
// 时
int hour = localDateTime.getHour();
// 分
int minute = localDateTime.getMinute();
// 秒
int second = localDateTime.getSecond();

System.out.println("年: " + year); // 2007
System.out.println("月: " + monthValue); // 8
System.out.println("一个月的第几日: " + dayOfMonth); // 20
System.out.println("一周的第几天:" + weekValue); // 1
System.out.println("时: " + hour); // 13
System.out.println("分: " + minute); // 27
System.out.println("秒: " + second); // 50

获取具体时间,只需要.get即可,后续根据IDEA给出的提示选择

修改时间方法

  • LocalDateTime、LocalDate、LocalTime都是不可变的,下列方法返回的是一个新的对象
方法名 说明
withHour、withMinute、withSecond、withNano 修改时间,返回新时间对象
plusHours、plusMinutes、plusSeconds、plusNanos 把某个字段时间进行增加操作,返回新时间对象
minusHours、minusMinutes、plusSeconds、plusNanos 把某个字段时间进行减小操作,返回新时间对象
equals、isBefore、isAfter 判断2个时间对象,是否相等,在前还是在后

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
LocalDateTime nowTime = LocalDateTime.now();
// 当前时间
System.out.println("当前时间:" + nowTime);

// minus:减去
System.out.println("减去一小时:" + nowTime.minusHours(1)); // 减去一小时:2020-07-30T17:18:59.818044600
System.out.println("减去一分钟:" + nowTime.minusMinutes(1)); // 减去一分钟:2020-07-30T18:17:59.818044600
System.out.println("减去一秒钟:" + nowTime.minusSeconds(1)); // 减去一秒钟:2020-07-30T18:18:58.818044600
System.out.println("减去一纳秒:" + nowTime.minusNanos(1)); // 减去一纳秒:2020-07-30T18:18:59.818044599

// plus:加
System.out.println("加上一小时:" + nowTime.plusHours(1)); // 加上一小时:2020-07-30T19:20:29.534092300
System.out.println("加上一分钟:" + nowTime.plusMinutes(1)); // 加上一分钟:2020-07-30T18:21:29.534092300
System.out.println("加上一秒钟:" + nowTime.plusSeconds(1)); // 加上一秒钟:2020-07-30T18:20:30.534092300
System.out.println("加上一纳秒:" + nowTime.plusNanos(1)); // 加上一纳秒:2020-07-30T18:20:29.534092301

// 直接修改
System.out.println("年份修改为2000年:" + nowTime.withYear(2000)); // 年份修改为2000年:2000-07-30T18:26:43.201030600
System.out.println("月份修改为12月:" + nowTime.withMonth(12)); // 月份修改为12月:2020-12-30T18:26:43.201030600
System.out.println("日期修改为08日:" + nowTime.withDayOfMonth(8));// 日期修改为08日:2020-07-08T18:26:43.201030600
System.out.println("小时修改为晚上八点:" + nowTime.withHour(20)); // 小时修改为晚上八点:2020-07-30T20:26:43.201030600
System.out.println("分钟修改为一刻钟:" + nowTime.withMinute(15)); // 分钟修改为一刻钟:2020-07-30T18:15:43.201030600
System.out.println("秒钟修改为59秒:" + nowTime.withSecond(59)); // 秒钟修改为59秒:2020-07-30T18:26:59.201030600
System.out.println("纳秒修改为555纳秒:" + nowTime.withNano(555)); // 纳秒修改为555纳秒:2020-07-30T18:26:43.000000555

时间格式化类

  • DateTimeFormatter:用于时间的格式化和解析
方法名 说明
static DateTimeFormatter ofPattern(格式) 获取格式对象
String format(时间对象) 按照指定方式格式化
LocalDateTime LocalDateTime.parse(“解析字符串”, 格式化对象) 解析为LocalDateTime对象
LocalDate LocalDate.parse(“解析字符串”, 格式化对象) 解析为LocalDate对象
LocalTime LocalTime.parse(“解析字符串”, 格式化对象) 解析为LocalTime对象

格式化示例:

1
2
3
4
5
6
7
LocalDateTime ldt = LocalDateTime.now();
System.out.println("没有经过格式化之前的日期:" + ldt); // 2020-07-30T18:36:16.995669600

// 获取格式化对象
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:nn");
String formatDate = dateTimeFormatter.format(ldt);
System.out.println("格式化后的日期:" + formatDate); // 2020-07-30 18:38:18:538572300

解析示例:

1
2
3
4
5
6
7
8
9
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss:nn");

LocalDateTime localDateTime = LocalDateTime.parse("2030-11-08 20:18:58:000000", dateTimeFormatter);
LocalDate localDate = LocalDate.parse("2030-11-08 20:18:58:000000", dateTimeFormatter);
LocalTime localTime = LocalTime.parse("2030-11-08 20:18:58:000000", dateTimeFormatter);

System.out.println("解析后的LocalDateTime:" + localDateTime); // 2030-11-08T20:18:58
System.out.println("解析后的LocalDate:" + localDate); // 2030-11-08
System.out.println("解析后的LocalTime:" + localTime); // 20:18:58

格式化中的MM和dd表示月份和日期必须是双位数的,比如8月8日就要写成08月08日

如果写成yyyy-M-d,那么就不会出现问题了,且12月12日这种双位数日期也可以正常处理

时间间隔类

  • Duration:用于计算两个时间间隔(秒、纳秒)
  • Period:用于计算两个日期间隔(年、月、日)
  • ChronoUnit:用于计算两个日期间隔(全能)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 当前时间
LocalDateTime now = LocalDateTime.now();

// 生日
LocalDateTime birthday = LocalDateTime.of(2018,7,29,19,0,0);
System.out.println("相差的年数:" + ChronoUnit.YEARS.between(birthday,now)); // 相差的年数:2
System.out.println("相差的月数:" + ChronoUnit.MONTHS.between(birthday,now)); // 相差的月数:24
System.out.println("相差的周数:" + ChronoUnit.WEEKS.between(birthday,now)); // 相差的周数:104
System.out.println("相差的天数:" + ChronoUnit.DAYS.between(birthday,now)); // 相差的天数:732
System.out.println("相差的时数:" + ChronoUnit.HOURS.between(birthday,now)); // 相差的时数:17568
System.out.println("相差的分数:" + ChronoUnit.MINUTES.between(birthday,now)); // 相差的分数:1054082
System.out.println("相差的秒数:" + ChronoUnit.MINUTES.between(birthday,now)); // 相差的秒数:1054082
System.out.println("相差的半天数:" + ChronoUnit.HALF_DAYS.between(birthday,now)); // 相差的半天数:1464
System.out.println("相差的十年数:" + ChronoUnit.DECADES.between(birthday,now)); // 相差的十年数:0
System.out.println("相差的百年数:" + ChronoUnit.CENTURIES.between(birthday,now)); // 相差的百年数:0
System.out.println("相差的千年数:" + ChronoUnit.MILLENNIA.between(birthday,now)); // 相差的千年数:0
System.out.println("相差的万年数:" + ChronoUnit.ERAS.between(birthday,now)); // 相差的万年数:0