常用API

Random

随机数Random的介绍

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
1.概念:	java.util.Random类就是用来产生随机数字的,也是一种引用类型
2.随机数Random类的使用步骤:
和Scanner的使用步骤是相同的
(1)导包(找到我们要使用的东西)
格式:
import 包名.类名;
import java.util.Random;
快捷键:
alt + 回车
注意:
a.java.lang包下的东西可以直接使用,不用导包
b.当前类和要使用的类,处于同一个包中,也不用导包
(2)创建对象
类名 对象名 = new 类名(...);
类名: 之前写代码时,class关键字后面的名称

创建Scanner类的对象: Scanner sc = new Scanner(System.in);//其中: System.in 是固定写法


创建Random类的对象: Random r = new Random();//其中: ()中什么都不用写,固定格式

(3)使用
Scanner中获取键盘录入的整数: int num = sc.nextInt();
Random中产生随机整数数字:
r.nextInt(): 产生一个int范围内(正负21亿)的随机数字
r.nextInt(int类型整数数字n): 产生一个0到n之间的随机数字(包含0,但是不包含n)
其中: 圆括号()中的int类型整数数字n表示产生随机数字的上限范围


3.练习:
(1)产生10int范围内的整数数字
(2)产生100100之间(包含0,但是不包含100)的整数数字
(3)产生101100之间(包含1,包含100)的整数数字
[1,100] --> [0,99] + 1 --> [0,100) + 1 --> r.nextInt(100) + 1

思考:
产生1066178之间(包含66,包含178)的整数数字

Random类的使用

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
练习:
(1)产生10int范围内的整数数字
(2)产生100100之间(包含0,但是不包含100)的整数数字
(3)产生215之间(包含1,包含5)的整数数字
(4)产生101100之间(包含1,包含100)的整数数字

public class Demo01Random {
public static void main(String[] args) {
//创建Random类的对象
Random r = new Random();

//(1)产生10个int范围内的整数数字
for (int i = 0; i < 10; i++) {
//产生1个int范围内的整数数字
int num = r.nextInt();
System.out.println(num);
}
System.out.println("---------------");

//(2)产生10个0到100之间(包含0,但是不包含100)的整数数字
//r.nextInt(100): 产生0到100之间的1个随机数字,但是可以产生0,一定不会产生100(包含0,不包含100) [0,100) <==> [0,99]
for (int i = 0; i < 10; i++) {
//产生1个0到100之间(包含0,但是不包含100)的整数数字
int num = r.nextInt(100);
System.out.println(num);
}
System.out.println("---------------");

//(3)产生2个1到5之间(包含1,包含5)的整数数字
/*
如果可以产生: 0,1,2,3,4 ==>[0,4] ==> [0,5) ==> r.nextInt(5)
之后: +1 r.nextInt(5) + 1
结果: 1,2,3,4,5
*/
for (int i = 0; i < 2; i++) {
//产生1个1到5之间(包含1,包含5)的整数数字
int num = r.nextInt(5) + 1;
System.out.println(num);
}
System.out.println("---------------");

//(4)产生10个1到100之间(包含1,包含100)的整数数字
/*
先产生0到99的随机数字(包含0,包含99) --> r.nextInt(100)
+1
结果是1到100的随机数字(包含1,包含100) --> r.nextInt(100) + 1
*/
for (int i = 0; i < 10; i++) {
//产生1个1到100之间(包含1,包含100)的整数数字
int num = r.nextInt(100) + 1;//[0,99]+1
System.out.println(num);
}
System.out.println("---------------");
//证明以上代码,确实可以产生1和100
while(true) {
//产生1个1到100之间(包含1,包含100)的整数数字
int num = r.nextInt(100) + 1;//[0,99]+1
System.out.println(num);
if (num == 1 || num == 100) {
break;
}
}
}
}
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
/*
练习:
产生10个66到178之间(包含66,包含178)的整数数字
[66,178] --> [0, 112] + 66 --> [0,113) + 66 --> r.nextInt(113) + 6
*/
public class Demo02Random {
public static void main(String[] args) {
//创建Random类的对象
Random r = new Random();
//产生10个66到178之间(包含66,包含178)的整数数字
for (int i = 0; i < 10; i++) {
//产生1个66到178之间(包含66,包含178)的整数数字
int num = r.nextInt(113)+66;
System.out.println(num);
}
System.out.println("-------------");
//证明以上方式,是可以产生最小值66和最大值178的
while (true) {
//产生1个66到178之间(包含66,包含178)的整数数字
int num = r.nextInt(113)+66;
System.out.println(num);
if (num == 66 || num == 178) {
break;
}
}
}
}

Random练习-猜数字

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1.需求:程序自动生成一个1-100之间(包含1,包含100)的数字,使用程序实现猜出这个数字是多少?

2.效果:
如果猜的数字比真实数字大,提示你猜的数据大了
如果猜的数字比真实数字小,提示你猜的数据小了
如果猜的数字与真实数字相等,提示恭喜你猜中了

3.使用的知识点:
(1)使用产生随机数字的Random类(1.导包 2.创建对象 3.使用: nextInt(100)+1)
(2)使用键盘录入Scanner类(1.导包 2.创建对象 3.使用: nextInt())
(3)使用if语句的第三种格式,比较用户输入的数字和产生的随机数字的大小关系
(4)用户多少次可以猜对,不确定,需要使用循环(死循环: while(true))
(5)用户猜测正确后,需要停止循环,使用break
4.实现步骤:
(1)创建产生随机数字的Random类的对象
(2)产生一个[1,100]之间的随机数字,保存到int变量guessNum中,以供用户猜测
(3)创建键盘录入Scanner类的对象
(4)以下步骤(5)-(6)是一个循环过程,因为用户多少次可以猜对,并不能确定,使用while(true)
(5)获取用户猜测的通过键盘录入的数字,保存到int变量inputNum中
(6)使用if语句的第三种个,对用户猜测的保存在inputNum中的数字 和 产生的保存在guessNum中的数字进行比较
a.如果 inputNum 大于 guessNum 提示"你猜的数据大了"
b.否则,如果 inputNum 小于 guessNum 提示"你猜的数据小了"
c.否则,如果 inputNum 等于 guessNum 提示"恭喜你猜中了",并使用break结束循环
注意: inputNum 等于 guessNum 条件 省略不写

图解分析:

image-20200427143245135

实现代码:

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
public class Demo03GuessNum {
public static void main(String[] args) {
//(1)创建产生随机数字的Random类的对象
Random r = new Random();

//(2)产生一个[1,100]之间的随机数字,保存到int变量guessNum中,以供用户猜测
//[1,100] --> [0, 99] + 1 --> [0,100) + 1 --> r.nextInt(100) + 1
int guessNum = r.nextInt(100) + 1;

//(3)创建键盘录入Scanner类的对象
Scanner sc = new Scanner(System.in);
//(4)以下步骤(5)-(6)是一个循环过程,因为用户多少次可以猜对,并不能确定,使用while(true)
while (true) {
//(5)获取用户猜测的通过键盘录入的数字,保存到int变量inputNum中
System.out.println("请输入您猜测的数字(1-100之间的整数):");
int inputNum = sc.nextInt();

//(6)使用if语句的第三种个,对用户猜测的保存在inputNum中的数字 和 产生的保存在guessNum中的数字进行比较
if (inputNum > guessNum) {
//a.如果 inputNum 大于 guessNum 提示"你猜的数据大了"
System.out.println("你猜的数据大了");
} else if (inputNum < guessNum) {
//b.否则,如果 inputNum 小于 guessNum 提示"你猜的数据小了"
System.out.println("你猜的数据小了");
} else {
//c.否则,如果 inputNum 等于 guessNum 提示"恭喜你猜中了",并使用break结束循环
//注意: inputNum 等于 guessNum 条件 省略不写
System.out.println("恭喜你猜中了");
//使用break结束循环
break;
}
}

}
}

Scanner

键盘录入的基本使用

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
45
数据输出: 把程序运行的结果数据输出到控制台,从而显示到屏幕上
数据输入: 获取用户从键盘上录入的数据到程序当中,然后程序根据业务需求,对获取到的数据进行相关处理

思考1:
像数据输入这样的操作使用非常频繁,而且实现起来比较复杂,jdk的开发人员已经把此功能实现好了
jdk中把获取键盘录入数据的功能放到了java.util包的Scanner类中

思考2: 如何使用键盘录入Scanner类呢?
java中的数据类型: 基本数据类型(四类八种)和引用数据类型(类,接口,数组,枚举...)
对于引用类型的使用有固定的使用步骤,而键盘录入Scanner类就是一个引用类型,使用也有固定的步骤

键盘录入Scanner的使用,有固定的3个步骤: ----固定格式,先记住
1.导包(找到我们要使用的东西,告诉jvm我们使用的东西在哪里)
格式:
import 包名.类名;
import java.util.Scanner;

2.创建对象:
格式:
类名 对象名 = new 类名(...);
类名: 就是之前写代码时class关键字后面的名字
Scanner sc = new Scanner(System.in);
注意: System.in是固定写法,后面就业班专门讲解

3.使用:
sc.nextInt(): 获取键盘录入的整数数字
4.练习:
获取键盘录入的一个int数字并输出到控制台
(1)导包: import java.util.Scanner;
(2)创建对象: Scanner sc = new Scanner(System.in);
(3)获取键盘录入的数字: sc.nextInt()

import java.util.Scanner;
public class Demo01Scanner {
public static void main(String[] args) {
//(1)导包: import java.util.Scanner;
//(2)创建对象: Scanner sc = new Scanner(System.in);
Scanner sc = new Scanner(System.in);

//(3)获取键盘录入的数字: sc.nextInt()
System.out.println("哥们,请您输入一个整数数字: ");
int num = sc.nextInt();
System.out.println("您输入的整数数字: "+num);
}
}

键盘录入的理解

image-20200423144716089

键盘录入的练习

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
需求:
获取键盘录入的两个整数(int类型)数字,在控制台输出求和的结果。

实现步骤:
1.导包: import java.util.Scanner
2.创建键盘录入Scanner类的对象: Scanner sc = new Scanner(System.in)
3.获取键盘录入的两个整数数字,分别保存到int变量a和b中
4.计算a和b的和,保存到int变量sum中
5.打印sum的值
public class Demo02ScannerSum {
public static void main(String[] args) {
//1.导包: import java.util.Scanner
//2.创建键盘录入Scanner类的对象: Scanner sc = new Scanner(System.in)
Scanner sc = new Scanner(System.in);

//3.获取键盘录入的两个整数数字,分别保存到int变量a和b中
System.out.println("请输入第一个整数数字: ");
int a = sc.nextInt();

System.out.println("请输入第二个整数数字: ");
int b = sc.nextInt();

System.out.println(a+"...."+b);

//4.计算a和b的和,保存到int变量sum中
int sum = a + b;

//5.打印sum的值
System.out.println("和: "+sum);
}
}

键盘录入改写三个和尚案例

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
需求:
一座寺庙里住着三个和尚,已知他们的身高分别为150cm、210cm、165cm,身高需要使用键盘录入
请用程序实现获取这三个和尚的最高身高。

实现步骤:
1.创建键盘录入Scanner类的对象(不用单独先自己写导包)
(1)写出单词Scanner,然后按alt + / 根据提示选择相应的类 会自动导包
(2)一边写,根据提示直接选择相应的类,回车会自动导包
2.获取键盘录入的三个整数数字,分别代表三个和尚的身高,分别保存到int变量h1,h2,h3中
3.使用三元运算符求出h1和h2的最大身高,保存到int变量temp中
4.使用三元运算符求出temp和h3的最大身高,保存到int变量max中
5.打印max的值
import java.util.Scanner;
public class Demo03ScannerMax {
public static void main(String[] args) {
//1.创建键盘录入Scanner类的对象(不用单独先自己写导包)
Scanner sc = new Scanner(System.in);
//2.获取键盘录入的三个整数数字,分别代表三个和尚的身高,分别保存到int变量h1,h2,h3中
System.out.println("请输入第一个和尚的身高(整数数字): ");
int h1 = sc.nextInt();

System.out.println("请输入第二个和尚的身高(整数数字): ");
int h2 = sc.nextInt();

System.out.println("请输入第三个和尚的身高(整数数字): ");
int h3 = sc.nextInt();

System.out.println(h1 + "..." + h2 + "..." + h3);

//3.使用三元运算符求出h1和h2的最大身高,保存到int变量temp中
int temp = (h1 > h2) ? h1 : h2;

//4.使用三元运算符求出temp和h3的最大身高,保存到int变量max中
int max = (temp>h3) ? temp : h3;

//5.打印max的值
System.out.println("三个和尚的最大身高: "+max);
}
}

String

String类概述

String 类代表字符串,Java 程序中的所有字符串文字(例如“abc”)都被实现为此类的实例。也就是说,Java 程序中所有的双引号字符串,都是 String 类的对象。String 类在 java.lang 包下,所以使用的时候不需要导包!

String类的特点

  • 字符串不可变,它们的值在创建后不能被更改
  • 虽然 String 的值是不可变的,但是它们可以被共享
  • 字符串效果上相当于字符数组( char[] ),但是底层原理是字节数组( byte[] )

String类的构造方法

  • 常用的构造方法

    方法名 说明
    public String() 创建一个空白字符串对象,不含有任何内容
    public String(char[] chs) 根据字符数组的内容,来创建字符串对象
    public String(byte[] bys) 根据字节数组的内容,来创建字符串对象
    String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc
  • 示例代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class StringDemo01 {
    public static void main(String[] args) {
    //public String():创建一个空白字符串对象,不含有任何内容
    String s1 = new String();
    System.out.println("s1:" + s1);

    //public String(char[] chs):根据字符数组的内容,来创建字符串对象
    char[] chs = {'a', 'b', 'c'};
    String s2 = new String(chs);
    System.out.println("s2:" + s2);

    //public String(byte[] bys):根据字节数组的内容,来创建字符串对象
    byte[] bys = {97, 98, 99};
    String s3 = new String(bys);
    System.out.println("s3:" + s3);

    //String s = “abc”; 直接赋值的方式创建字符串对象,内容就是abc
    String s4 = "abc";
    System.out.println("s4:" + s4);
    }
    }

创建字符串对象两种方式的区别

  • 通过构造方法创建

    通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,虽然内容相同,但是地址值不同

  • 直接赋值方式创建

    以“”方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会建立一个 String 对象,并在字符串池中维护

字符串的比较

==号的作用

  • 比较基本数据类型:比较的是具体的值
  • 比较引用数据类型:比较的是对象地址值

equals方法的作用

  • 方法介绍

    1
    public boolean equals(String s)     比较两个字符串内容是否相同、区分大小写
  • 示例代码

    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 StringDemo02 {
    public static void main(String[] args) {
    //构造方法的方式得到对象
    char[] chs = {'a', 'b', 'c'};
    String s1 = new String(chs);
    String s2 = new String(chs);

    //直接赋值的方式得到对象
    String s3 = "abc";
    String s4 = "abc";

    //比较字符串对象地址是否相同
    System.out.println(s1 == s2);
    System.out.println(s1 == s3);
    System.out.println(s3 == s4);
    System.out.println("--------");

    //比较字符串内容是否相同
    System.out.println(s1.equals(s2));
    System.out.println(s1.equals(s3));
    System.out.println(s3.equals(s4));
    }
    }

用户登录案例

案例需求

已知用户名和密码,请用程序实现模拟用户登录。总共给三次机会,登录之后,给出相应的提示

代码实现

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
public class Test1登录案例 {
public static void main(String[] args) {
//1.定义两个变量用来记录正确的用户名和密码
String rightUsername = "itheima";
String rightPassword = "1234qwer";

//2.键盘录入用户名和密码
//ctrl + alt + T 选择包裹方式

for (int i = 0; i < 3; i++) {//0 1 2
Scanner sc = new Scanner(System.in);
System.out.println("请输入用户名");
String username = sc.next();
System.out.println("请输入密码");
String password = sc.next();

//3.判断比较
if (username.equals(rightUsername) && password.equals(rightPassword)) {
System.out.println("登录成功");
//如果正确,循环结束
break;
} else {
//最后一次机会
if(i == 2){
System.out.println("账户" + username + "被锁定,请联系黑马程序员官方小姐姐:XXXXXXX");
}else{
//不是最后一次机会
System.out.println("用户名或密码错误,登录失败,还剩下" + (2 - i) + "次机会");//2 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
public class Test2字符串直接遍历 {
public static void main(String[] args) {
//两个方法:
//charAt():会根据索引获取对应的字符
//length(): 会返回字符串的长度


//1.键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入字符串");
String str = sc.next();
System.out.println(str);

//2.遍历
for (int i = 0; i < str.length(); i++) {
//i 依次表示字符串的每一个索引
//索引的范围:0 ~ 长度-1

//根据索引获取字符串里面的每一个字符
//ctrl + alt + V 自动生成左边的接受变量
char c = str.charAt(i);
System.out.println(c);
}
}
}

统计字符次数案例

案例需求

键盘录入一个字符串,统计该字符串中大写字母字符,小写字母字符,数字字符出现的次数(不考虑其他字符)

代码实现

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
public class Test4统计个数 {
public static void main(String[] args) {
//键盘录入一个字符串,统计大写,小写,数字出现的次数


//1.键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String str = sc.next();


//2.统计 --- 计数器count
//此时我要统计的有3样东西,所以要定义3个计数器分别进行统计
int bigCount = 0;
int smallCount = 0;
int numberCount = 0;
//得到这个字符串里面每一个字符
for (int i = 0; i < str.length(); i++) {
//i 表示字符串中的索引
//c 表示字符串中的每一个字符
char c = str.charAt(i);

//对c进行判断
if (c >= 'a' && c <= 'z') {
smallCount++;
}else if(c >= 'A' && c <= 'Z'){
bigCount++;
}else if(c >= '0' && c <= '9'){
numberCount++;
}
}

//3.当循环结束之后,三个变量记录的就是对应的个数
System.out.println("大写字符有:" + bigCount + "个");
System.out.println("小写字符有:" + smallCount + "个");
System.out.println("数字字符有:" + numberCount + "个");
}
}

字符串拼接案例

案例需求

定义一个方法,把 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
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
public class Test5数组拼接成字符串 {
public static void main(String[] args) {
//定义一个方法,把 int 数组中的数据按照指定的格式拼接成一个字符串返回,调用该方法,
//并在控制台输出结果。例如,数组为 int[] arr = {1,2,3};
//执行方法后的输出结果为:[1, 2, 3]


int[] arr = {1, 2, 3, 4, 5};

String str = arrToString(arr);
System.out.println(str);

}


//作用:把一个数组变成字符串
public static String arrToString(int[] arr) {
String s = "";
//拼接左括号
s = s + "["; //此时是拿着长度为0的字符串,跟[进行拼接,产生一个新的字符串。
//把新的字符串再赋值给s,此时变量s记录的就是新的字符串"["的地址值

//下面我想得到数组里面的每一个元素并进行拼接
//那么就需要遍历数组,得到每一个元素才行
for (int i = 0; i < arr.length; i++) {
//假设第一次循环:i = 0 获取的就是0索引上的元素
//在拼接的时候:"[" + 1 + ", " 拼接完毕之后产生一个新的字符串 "[1, "
//第二次循环:i = 1 获取的就是1索引上的元素
//在拼接的时候: 此时s就是第一次循环结束后拼接完毕的结果:"[1, "
//在拼接的时候:"[1, " + 2 + ", " 拼接完毕之后产生一个新的字符串 "[1, 2, "
//...
if(i == arr.length - 1){
//如果是最后一个元素,那么不需要拼接逗号空格
s = s + arr[i];
}else{
//如果不是最后一个元素,需要拼接元素和逗号空格
s = s + arr[i] + ", ";
}
}

//等循环结束之后,再拼接最后一个右括号
s = s + "]";

return s;

}


//用来遍历数组
public static void printArr(int[] arr) {
System.out.print("[");
for (int i = 0; i < arr.length; i++) {
if (i == arr.length - 1) {
System.out.print(arr[i]);
} else {
System.out.print(arr[i] + ", ");
}
}
System.out.println("]");

//[1, 2, 3, 4, 5]
//我们现在要知道,这个最终结果是怎么来的?
//从到右依次打印得来的。
}
}

字符串反转案例

案例需求

定义一个方法,实现字符串反转。键盘录入一个字符串,调用该方法后,在控制台输出结果

例如,键盘录入 abc,输出结果 cba

代码实现

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
public class Test6反转字符串 {
public static void main(String[] args) {
/*定义一个方法,实现字符串反转。键盘录入一个字符串,调用该方法后,在控制台输出结果
例如,键盘录入 abc,输出结果 cba*/



//1.定义一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String str = sc.next();
//2.定义一个方法,反转字符串
//abc ---> cba
//可以把字符串倒着遍历,再拼接
String result = reverse(str);
System.out.println(result);


}

//注释:方法的作用就是反转字符串
//把传递进来的字符串进行反转
public static String reverse(String str){//abc
//核心思想:倒着遍历并进行拼接就可以了
//fori :正着遍历 forr:倒着遍历
String s = "";
for (int i = str.length() - 1; i >= 0; i--) {
//i 依次表示字符串里面的每一个索引(倒着的)
//我们就可以拿到里面的每一个字符并拼接
s = s + str.charAt(i);
}

//把倒着拼接之后的结果返回即可
return s;

}
}

金额转换

案例需求

把2135变成:零佰零拾零万贰仟壹佰叁拾伍元

把789变成:零佰零拾零万零仟柒佰捌拾玖元

代码实现

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
package com.itheima.stringdemo;

import java.util.Scanner;

public class StringDemo9 {
public static void main(String[] args) {
//1.键盘录入一个金额
Scanner sc = new Scanner(System.in);
int money;
while (true) {
System.out.println("请录入一个金额");
money = sc.nextInt();
if (money >= 0 && money <= 9999999) {
break;
} else {
System.out.println("金额无效");
}
}

//定义一个变量用来表示钱的大写
String moneyStr = "";

//2.得到money里面的每一位数字,再转成中文
while (true) {//2135
//从右往左获取数据,因为右侧是数据的个位
int ge = money % 10;
String capitalNumber = getCapitalNumber(ge);
//把转换之后的大写拼接到moneyStr当中
moneyStr = capitalNumber + moneyStr;
//第一次循环 : "伍" + "" = "伍"
//第二次循环 : "叁" + "伍" = "叁伍"
//去掉刚刚获取的数据
money = money / 10;

//如果数字上的每一位全部获取到了,那么money记录的就是0,此时循环结束
if (money == 0) {
break;
}
}

//3.在前面补0,补齐7位
int count = 7 - moneyStr.length();
for (int i = 0; i < count; i++) {
moneyStr = "零" + moneyStr;
}
System.out.println(moneyStr);//零零零贰壹叁伍

//4.插入单位
//定义一个数组表示单位
String[] arr = {"佰","拾","万","仟","佰","拾","元"};
// 零 零 零 贰 壹 叁 伍

//遍历moneyStr,依次得到 零 零 零 贰 壹 叁 伍
//然后把arr的单位插入进去

String result = "";
for (int i = 0; i < moneyStr.length(); i++) {
char c = moneyStr.charAt(i);
//把大写数字和单位拼接到result当中
result = result + c + arr[i];
}

//5.打印最终结果
System.out.println(result);

}


//定义一个方法把数字变成大写的中文
//1 -- 壹
public static String getCapitalNumber(int number) {
//定义数组,让数字跟大写的中文产生一个对应关系
String[] arr = {"零", "壹", "贰", "叁", "肆", "伍", "陆", "柒", "捌", "玖"};
//返回结果
return arr[number];
}

}

手机号屏蔽

需求:以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽

最终效果为:131****9468

代码实现:

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
public class Test8手机号屏蔽 {
public static void main(String[] args) {
/*以字符串的形式从键盘接受一个手机号,将中间四位号码屏蔽
最终效果为:131****9468*/

//1.键盘录入一个手机号码
Scanner sc = new Scanner(System.in);
System.out.println("请输入手机号码");
String phoneNumber = sc.next();//13112349408

//2.截取手机号码中的前三位
String star = phoneNumber.substring(0, 3);

//3.截取手机号码中的最后四位
//此时我用substring方法,是用1个参数的,还是两个参数的?1个参数的会更好
//因为现在我要截取到最后,所以建议使用1个参数的。
String end = phoneNumber.substring(7);

//4.拼接
String result = star + "****" + end;

System.out.println(result);

}
}

敏感词替换

需求1:键盘录入一个 字符串,如果字符串中包含(TMD),则使用***替换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Test9敏感词替换 {
public static void main(String[] args) {
//1.定义一个变量表示骂人的话
String talk = "后裔你玩什么啊,TMD";


//2.把这句话中的敏感词进行替换
String result = talk.replace("TMD", "***");

//3.打印
System.out.println(talk);
System.out.println(result);
}
}

需求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
25
public class Test10多个敏感词替换 {
public static void main(String[] args) {
//实际开发中,敏感词会有很多很多

//1.先键盘录入要说的话
Scanner sc = new Scanner(System.in);
System.out.println("请输入要说的话");
String talk = sc.next();//后裔你玩什么啊,TMD,GDX,ctmd,ZZ

//2.定义一个数组用来存多个敏感词
String[] arr = {"TMD","GDX","ctmd","ZZ","lj","FW","nt"};

//3.把说的话中所有的敏感词都替换为***

for (int i = 0; i < arr.length; i++) {
//i 索引
//arr[i] 元素 --- 敏感词
talk = talk.replace(arr[i],"***");
}

//4.打印结果
System.out.println(talk);//后裔你玩什么啊,***,***,***,***

}
}

身份证信息查看

身份证的每一位都是有固定的含义:

  • 1、2位:省份
  • 3、4位:城市
  • 5、6位:区县
  • 7-14位:出生年、月、日
  • 15、16位:所在地派出所
  • 17位:性别(奇数男性,偶数女性)
  • 18位:个人信息码(随机产生)

要求打印内容方式如下:

人物信息为:

出生年月日:XXXX年X月X日

性别为:男/女

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
package com.itheima.stringdemo;

public class StringDemo11 {
public static void main(String[] args) {
//1.定义一个字符串记录身份证号码
String id = "321281202001011234";

//2.获取出生年月日
String year = id.substring(6, 10);
String month = id.substring(10, 12);
String day = id.substring(12, 14);


System.out.println("人物信息为:");
System.out.println("出生年月日:" + year + "年" + month + "月" + day + "日");

//3.获取性别
char gender = id.charAt(16);//'3' ---> 3
//利用ASCII码表进行转换
//'0' ---> 48
//'1' ---> 49
//'2' ---> 50
//'3' ---> 51
//'4' ---> 52
//'5' ---> 53
//'6' ---> 54
//'7' ---> 55
//'8' ---> 56
//'9' ---> 57

int num = gender - 48;
if(num % 2 == 0){
System.out.println("性别为:女");
}else{
System.out.println("性别为:男");
}
}
}

StringBuilder

StringBuilder 可以看成是一个容器,创建之后里面的内容是可变的。

当我们在拼接字符串和反转字符串的时候会使用到

基本使用

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
public class StringBuilderDemo3 {
public static void main(String[] args) {
//1.创建对象
StringBuilder sb = new StringBuilder("abc");

//2.添加元素
/*sb.append(1);
sb.append(2.3);
sb.append(true);*/

//反转
sb.reverse();

//获取长度
int len = sb.length();
System.out.println(len);


//打印
//普及:
//因为StringBuilder是Java已经写好的类
//java在底层对他做了一些特殊处理。
//打印对象不是地址值而是属性值。
System.out.println(sb);
}
}

链式编程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class StringBuilderDemo4 {
public static void main(String[] args) {
//1.创建对象
StringBuilder sb = new StringBuilder();

//2.添加字符串
sb.append("aaa").append("bbb").append("ccc").append("ddd");

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

//3.再把StringBuilder变回字符串
String str = sb.toString();
System.out.println(str);//aaabbbcccddd

}
}

练习1:对称字符串

需求:

键盘接受一个字符串,程序判断出该字符串是否是对称字符串,并在控制台打印是或不是

1
2
3
对称字符串:123321111

非对称字符串:123123

代码示例:

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 StringBuilderDemo6 {
//使用StringBuilder的场景:
//1.字符串的拼接
//2.字符串的反转

public static void main(String[] args) {
//1.键盘录入一个字符串
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String str = sc.next();

//2.反转键盘录入的字符串
String result = new StringBuilder().append(str).reverse().toString();

//3.比较
if(str.equals(result)){
System.out.println("当前字符串是对称字符串");
}else{
System.out.println("当前字符串不是对称字符串");
}

}
}

练习2:拼接字符串

需求:定义一个方法,把 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
24
25
26
27
28
29
30
31
package com.itheima.stringbuilderdemo;

public class StringBuilderDemo7 {
public static void main(String[] args) {
//1.定义数组
int[] arr = {1,2,3};

//2.调用方法把数组变成字符串
String str = arrToString(arr);

System.out.println(str);

}


public static String arrToString(int[] arr){
StringBuilder sb = new StringBuilder();
sb.append("[");

for (int i = 0; i < arr.length; i++) {
if(i == arr.length - 1){
sb.append(arr[i]);
}else{
sb.append(arr[i]).append(", ");
}
}
sb.append("]");

return sb.toString();
}
}

相较于String + ,StringBuilder更快,大概是3s和0.3s的区别

StringJoiner

  • StringJoiner跟StringBuilder一样,也可以看成是一个容器,创建之后里面的内容是可变的。
  • 作用:提高字符串的操作效率,而且代码编写特别简洁,但是目前市场上很少有人用。
  • JDK8出现的

基本使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//1.创建一个对象,并指定中间的间隔符号
StringJoiner sj = new StringJoiner("---");
//2.添加元素
sj.add("aaa").add("bbb").add("ccc");
//3.打印结果
System.out.println(sj);//aaa---bbb---ccc
//1.创建对象
StringJoiner sj = new StringJoiner(", ","[","]");
//2.添加元素
sj.add("aaa").add("bbb").add("ccc");
int len = sj.length();
System.out.println(len);//15
//3.打印
System.out.println(sj);//[aaa, bbb, ccc]
String str = sj.toString();
System.out.println(str);//[aaa, bbb, ccc]

关于字符串的小扩展:

  1. 字符串存储的内存原理

    String s = “abc”;直接赋值

    特点:

    此时字符串abc是存在字符串常量池中的。

    先检查字符串常量池中有没有字符串abc,如果有,不会创建新的,而是直接复用。如果没有abc,才会创建一个新的。

    所以,直接赋值的方式,代码简单,而且节约内存。

  2. new出来的字符串

    看到new关键字,一定是在堆里面开辟了一个小空间。

    String s1 = new String(“abc”);

    String s2 = “abc”;

    s1记录的是new出来的,在堆里面的地址值。

    s2是直接赋值的,所以记录的是字符串常量池中的地址值。

  3. ==号比较的到底是什么?

    如果比较的是基本数据类型:比的是具体的数值是否相等。

    如果比较的是引用数据类型:比的是地址值是否相等。

    结论:==只能用于比较基本数据类型。不能比较引用数据类型。

包装类&装箱拆箱

基本类型包装类

基本类型包装类的作用

  • 将基本数据类型封装成对象的好处在于可以在对象中定义更多的功能方法操作该数据
  • 常用的操作之一:用于基本数据类型与字符串之间的转换

基本类型对应的包装类

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

Integer类

包装一个对象中的原始类型 int 的值

方法名 说明
public Integer(int value) 根据 int 值创建 Integer 对象**(过时)**
public Integer(String s) 根据 String 值创建 Integer 对象**(过时)**
public static Integer valueOf(int i) 返回表示指定的 int 值的 Integer 实例
public static Integer valueOf(String s) 返回一个保存指定值的 Integer 对象 String

自动拆箱和自动装箱

自动装箱

  • 把基本数据类型转换为对应的包装类类型

自动拆箱

  • 把包装类类型转换为对应的基本数据类型

自动拆装箱是JDK1.5新特性,可以实现基本数据类型与对应的包装类之间无缝使用!

image-20230622080906287

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
public class IntergerDemo3 {
public static void main(String[] args) {
Integer i1 = 100;
// 对象 = 默认是一个基本数据类型

// jdk1.5的特性 --- 自动装箱

//装箱: 把一个基本数据类型 变量对应的包装类.
//自动: Java底层会帮我们自动的调用valueof方法.
System.out.println("自动装箱i1为interger:"+i1);

//jdk1.5的特性 --- 自动拆箱
//拆箱: 把一个包装类型 变成对应的基本数据类型
int i2 = i1;
System.out.println("自动拆箱i2为int:"+i2);

Integer i3 = 100; //自动装箱机制
i3 += 200;//i3 = i3 + 200;
//会把i3这个对象变成基本数据类型100.
//100 + 200 = 300
//把基本数据类型300再次自动装箱变成Integer对象赋值给i3
System.out.println("自动拆装箱,最后i3为Interger类型:"+i3);


//细节:
Integer i4 = null;
if (i4 != null) {
i4 += 200; // 如果i4是null,无法转为基本数据类型,会报错
System.out.println(i4);
}
}
}

int类型如何转为String类型

  • 第一种方式:直接在int类型数据后面一个空字符串
  • 第二种方式:通过String的静态方法valueOf()

String类型如何转为int类型

  • 第一种方式:先将String转为Integer类型,再通过valueOf()方法转为int
  • 第二种方式:通过Integer静态方法parseInt()

Math

1、Math类概述

Math 包含执行基本数字运算的方法

2、Math中方法的调用方式

Math类中无构造方法,但内部的方法都是静态的,则可以通过 类名.进行调用

3、Math类的常用方法

1
2
3
4
5
6
7
8
public static int abs(int a)	返回参数的绝对值
public static double ceil(double a) 返回大于或等于参数的最小double值,等于一个整数
public static double floor(double a) 返回小于或等于参数的最大double值,等于一个整数
public static int round(float a) 按照四舍五入返回最接近参数的int
public static int max(int a,int b) 返回两个int值中的较大值
public static int min(int a,int b) 返回两个int值中的较小值
public static double pow (double a,double b) 返回a的b次幂的值
public static double random() 返回值为double的正值,[0.0,1.0)

4、举例子

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
45
46
47
48
49
package Nomal_API.APIdemo;


public class MathDemo {
public static void main(String[] args) {
// public static int abs(int a); //返回参数的绝对值
int abs = Math.abs(10);
System.out.println("abs的绝对值为:"+abs);


// public static double ceil(double a); //向上取整
double ceil = Math.ceil(10.1);
System.out.println("ceil的向上取整:"+ceil);


// public static double floor(double a); //向下取整
double floor = Math.floor(10.9);
System.out.println("floor的向下取整为:"+floor);


// public static int round(float a); //四舍五入
long round = Math.round(10.1);
System.out.println("round的四舍五入为:"+round);

long round1 = Math.round(1.9);
System.out.println("round1的四舍五入为:"+round1);
// public static int max(int a,int b); //返回两个int值中的较大值
int max = Math.max(10, 20);
System.out.println("max的最大值为:"+max);


// public static int min(int a,int b); //返回两个int值中的较小值
int min = Math.min(10, 20);
System.out.println("min的最小值为:"+min);


// public static double pow(double a,double b); //返回a的b次幂的值
double pow = Math.pow(2, 3);
System.out.println("pow的幂次方为:"+pow);


// public static double random(); //返回值为double的正值,[0.0,1.0)
System.out.println("随机值【double类型】");
for (int i = 0; i < 10 ; i++) {
double random = Math.random();
System.out.println(random);
}
}
}

System

1、方法

1
2
public static void exit(int status)	终止当前运行的 Java 虚拟机,非零表示异常终止
public static long currentTimeMillis() 返回当前时间(以毫秒为单位)

2、例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Systemdemo {
public static void main(String[] args) {
// 获取开始的时间节点
long start = System.currentTimeMillis();
System.out.println("开始时间为"+start);
int i;
for (i = 1; i <= 10000; i++) {
int c = 0;
c += i;
}
// 获取代码运行结束后的时间节点
long end = System.currentTimeMillis();
System.out.println("结束时间为:"+end);
System.out.println("循环"+i+"共耗时:" + (end - start) + "毫秒");
}
}

Object

概述

java.lang.Object类是Java语言中的根类,即所有类的父类。它中描述的所有方法子类都可以使用。在对象实例化的时候,最终找的父类就是Object。

如果一个类没有特别指定父类, 那么默认则继承自Object类。例如:

1
2
3
public class MyClass /*extends Object*/ {
// ...
}

根据JDK源代码及Object类的API文档,Object类当中包含的方法有11个。今天我们主要学习其中的2个:

  • public String toString():返回该对象的字符串表示。
  • public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。

toString方法

方法摘要

  • public String toString():返回该对象的字符串表示。

  • toString方法返回该对象的字符串表示,其实该字符串内容就是对象的类型+@+内存地址值。

由于toString方法返回的结果是内存地址,而在开发中,经常需要按照对象的属性得到相应的字符串表现形式,因此也需要重写它

覆盖重写

如果不希望使用toString方法的默认行为,则可以对它进行覆盖重写。例如自定义的Person类:

1
2
3
4
5
6
7
8
9
10
11
12
public class Person {  
private String name;
private int age;

@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}

// 省略构造器与Getter Setter
}

在IntelliJ IDEA中,可以点击Code菜单中的Generate…,也可以使用快捷键alt+insert,点击toString()选项。选择需要包含的成员变量并确定。如下图所示:

equals方法

方法摘要

  • public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。

调用成员方法equals并指定参数为另一个对象,则可以判断这两个对象是否是相同的。这里的“相同”有默认和自定义两种方式。

默认地址比较

如果没有覆盖重写equals方法,那么Object类中默认进行==运算符的对象地址比较,只要不是同一个对象,结果必然为false。

对象内容比较

如果希望进行对象的内容比较,即所有或指定的部分成员变量相同就判定两个对象相同,则可以覆盖重写equals方法。例如:

1
2
3
4
5
6
7
8
9
10
11
12
public class Person {  
private String name;
private int age;

@Override
public String toString() {
return "Person{" + "name='" + name + '\'' + ", age=" + age + '}';
}

// 省略构造器与Getter Setter
}

这段代码充分考虑了对象为空、类型一致等问题,但方法内容并不唯一。大多数IDE都可以自动生成equals方法的代码内容。在IntelliJ IDEA中,可以使用Code菜单中的Generate…选项,也可以使用快捷键alt+insert,并选择equals() and hashCode()进行自动代码生成。

Objects

1、方法

1
2
3
4
public static String toString (对象)	返回参数中对象的字符串表示形式。
public static String toString(对象, 默认字符串) 返回对象的字符串表示形式。
public static Boolean isNull(对象) 判断对象是否为空
public static Boolean nonNull(对象) 判断对象是否不为空

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
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
class Student {
private String name;
private int age;

public Student() {
}

public Student(String name, int age) {
this.name = name;
this.age = age;
}

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public int getAge() {
return age;
}

public void setAge(int age) {
this.age = age;
}

@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}

}
import java.util.Objects;

public class MyObjectsDemo {
public static void main(String[] args) {
// public static String toString(对象): 返回参数中对象的字符串表示形式。
Student s1 = new Student("小小同学",50);
String result1 = Objects.toString(s1);
System.out.println(result1); // 打印toString方法
System.out.println(s1);

// public static String toString(对象, 默认字符串): 返回对象的字符串表示形式。如果对象为空,那么返回第二个参数.
Student s2 = new Student("小花同学",23);
Student s3 = null;
String result2 = Objects.toString(s3, "随便写一个");
System.out.println(result2);

// public static Boolean isNull(对象): 判断对象是否为空
Student s4 = null;
Student s5 = new Student();
boolean result3 = Objects.isNull(s5);
System.out.println("对象是否为空:"+result3);

// public static Boolean nonNull(对象): 判断对象是否不为空
Student s6 = new Student();
Student s7 = null;
boolean result4 = Objects.nonNull(s6); // 判断对象是否不为空
System.out.println("对象是否不为空"+ result4);
}

}

BigDecimal

1、作用

可以用来进行精确计算

2、构造方法

1
2
BigDecimal(double val)	参数为double
BigDecimal(String val) 参数为String

3、常用方法

1
2
3
4
5
6
7
8
9
public BigDecimal add(另一个BigDecimal对象)	加法
public BigDecimal subtract (另一个BigDecimal对象) 减法
public BigDecimal multiply (另一个BigDecimal对象) 乘法
public BigDecimal divide (另一个BigDecimal对象) 除法
public BigDecimal divide (另一个BigDecimal对象,精确几位,舍入模式) 除法
舍入模式:
BigDecimal.ROUND_UP 进一法
BigDecimal.ROUND_FLOOR 去尾法
BigDecimal.ROUND_HALF_UP 四舍五入

4、例子

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
45
46
47
48
49
50
51
52
53
54
55
56
package Nomal_API.APIdemo.bigdecimal;

import java.math.BigDecimal;

public class BigdecimalDemo {
public static void main(String[] args) {
BigDecimal bd1 = new BigDecimal("10.0");
BigDecimal bd2 = new BigDecimal("0.4");

System.out.println("字符串数字"+bd1);
System.out.println(bd2);

// BigDecimal bd1 = new BigDecimal(0.1);
// BigDecimal bd2 = new BigDecimal(0.2);
BigDecimal bd3 = new BigDecimal("0.1"); // 一定要用字符串!!!最准确
BigDecimal bd4 = new BigDecimal("0.2");
// public BigDecimal add(另一个BigDecimal对象) 加法
BigDecimal add = bd3.add(bd4); // 加法
System.out.println("和为" + add);
//System.out.println(0.1 + 0.2);


// public BigDecimal subtract (另一个BigDecimal对象) 减法
BigDecimal subtract = bd3.subtract(bd4);
System.out.println("差为" + subtract);

// public BigDecimal multiply (另一个BigDecimal对象) 乘法
BigDecimal multiply = bd1.multiply(bd2);
System.out.println("积为" + multiply);
// public BigDecimal divide (另一个BigDecimal对象) 除法
BigDecimal divide = bd1.divide(bd2); // 除出来为无理数则会报错
System.out.println("商为" + divide);
}
}

import java.math.BigDecimal;

public class MyBigDecimalDemo4 {
public static void main(String[] args) {
BigDecimal bd1 = new BigDecimal("0.3");
BigDecimal bd2 = new BigDecimal("4"); //0.075

/* BigDecimal divide = bd1.divide(bd2);
System.out.println(divide);*/

//参数一:表示参数运算的另一个对象
//参数二:表示小数点后精确到多少位
//参数三:舍入模式
//进一法 BigDecimal.ROUND_UP
//去尾法 BigDecimal.ROUND_FLOOR
//四舍五入 BigDecimal.ROUND_HALF_UP
BigDecimal divide = bd1.divide(bd2, 2, BigDecimal.ROUND_HALF_UP);
System.out.println(divide);
}

}

时间日期类

Date类

java.util.Date代表了一个特定的时间,精确到毫秒

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.DateTest1;

import java.util.Date;

public class DateDemo1 {
public static void main(String[] args) {
// public Date(); 分配一个Date对象,并初始化,以便它代表被分配的时间,精确到毫秒
Date d1 = new Date();
System.out.println(d1);

// public Date(long date): 分配一个Date对象,并将其初始化为表示从标准时间起指定的毫秒数
long date = 1000 * 60 * 60;
Date d2 = new Date(date);
System.out.println(d2);
}
}

tips: 由于我们处于东八区,所以我们的基准时间为1970年1月1日8时0分0秒。

Date类常用方法

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

import java.util.Date;

public class DateDemo2 {
public static void main(String[] args) {
// 创建日期对象
Date d = new Date();

// public long getTime(): 获取的是日期对象从1970年1月1日 00:00:00到现在的毫秒数值
System.out.println(d.getTime());
System.out.println(d.getTime() * 1.0 / 1000 / 60 / 60 / 24 / 365 + "年");
System.out.println("----------------------");

// public void setTime(long time): 设置时间,给的是毫秒数
long time = 1000 * 60 * 60;
d.setTime(time);
System.out.println(d);
}
}

SimpleDateFormat类

SimpleDateFormat是一个具体的类,用于以区域设置敏感的方式格式化和解析日期

常用方法

  • 格式化(从Date到String):public final String format(Date date): 将日期格式化成日期/时间字符串
  • 解析(从String到Date):public Date parse(String source): 从给定字符串的开始解析文本以生成日期

示例

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
package com.SimpleDateFormatTest1;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class SimpleDateFormatDemo {
public static void main(String[] args) throws ParseException {
// 格式化:从Date到String
Date d = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss");
String s = sdf.format(d);
System.out.println(s);
System.out.println("---------");

// 从String到Date
String ss = "2048-08-09 11:11:11";
// ParseException
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date dd = sdf2.parse(ss);
System.out.println(dd);

}

}

日期工具类案例

需求:定义一个日期工具类(DateUtils),包含两个方法:把日期转换为指定格式的字符串;把字符串解析成指定格式的日期,然后定义一个测试类(DateDemo),测试日期工具类的方法

工具类:

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
package com.DateSDFTest2;

import java.text.ParseException;
import java.util.Date;

public class DateSDFDemo {
public static void main(String[] args) throws ParseException {
// 创建日期对象
Date d = new Date();

String s1 = DateUtils.dateToString(d, "yyyy年MM月dd日 HH:mm:ss");
System.out.println(s1);

String s2 = DateUtils.dateToString(d, "yyyy年MM月dd日");
System.out.println(s2);

String s3 = DateUtils.dateToString(d, "HH:mm:ss");
System.out.println(s3);
System.out.println("--------");

String s = "2048-08-08 12:12:12";
Date dd = DateUtils.stringToDate(s, "yyyy-MM-dd HH:mm:ss");
System.out.println(dd);

}

}

Calender类

Calendar为特定瞬间与一组日历字段之间的转换提供了一些方法,并为操作日历字段提供了一些方法

Calendar提供了一个类方法getinstance用于获取这种类型的一般有用的对象

  • 该方法返回一个Calendar对象
  • 其日历字段已使用当前日期和时间初始化:Calendar rightNow = Calendar.getInstance();

常用方法

示例

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
package com.CalendarTest;

import java.util.Calendar;

public class CalendarDemo {
public static void main(String[] args) {
// 获取日历类对象
Calendar c = Calendar.getInstance();

// public int get(int field): 返回给定日历字段的值
int year = c.get(Calendar.YEAR);
int month = c.get(Calendar.MONTH) + 1;
int date = c.get(Calendar.DATE);
System.out.println(year + "年" + month + "月" + date + "日");

// public abstract void add(int filed, int amount): 根据日历规则,将指定的时间量添加或减去给定的日历字段
// 需求1: 3年前的今天
c.add(Calendar.YEAR, -3);
year = c.get(Calendar.YEAR);
month = c.get(Calendar.MONTH) + 1;
date = c.get(Calendar.DATE);
System.out.println(year + "年" + month + "月" + date + "日");

// 需求2:10年后的10天前
c.add(Calendar.YEAR, 10);
c.add(Calendar.DATE, -10);
year = c.get(Calendar.YEAR);
month = c.get(Calendar.MONTH) + 1;
date = c.get(Calendar.DATE);
System.out.println(year + "年" + month + "月" + date + "日");

// public final void set(int year, int month, int date): 设置当前日历的年月日
c.set(2050, 10, 10);
year = c.get(Calendar.YEAR);
month = c.get(Calendar.MONTH) + 1;
date = c.get(Calendar.DATE);
System.out.println(year + "年" + month + "月" + date + "日");

}

}

二月天案例

​ 需求:获取任意一年的二月有多少天

示例

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 com.CalendarTest;

import java.util.Calendar;
import java.util.Scanner;

public class CalendarTest {
public static void main(String[] args) {
// 键盘录入任意年份
Scanner sc = new Scanner(System.in);
System.out.println("请输入年:");
int year = sc.nextInt();

// 设置日历对象的年,月,日
Calendar c = Calendar.getInstance();
c.set(year, 2, 1);

// 3月1日前推一天,就是2月的最后一天
c.add(Calendar.DATE, -1);

// 获取这一天输出即可
int date = c.get(Calendar.DATE);
System.out.println(year + "年的2月分有" + date + "天");
}

}

JDK8以后

LocalDateTime

JDK8及之后的新日期时间API
JDK 1.0 中包含了一个 java.util.Date 类,但是它的大多数方法已经在 JDK 1.1 引入 Calendar 类之后被弃用了。而 Calendar 并不比 Date 好多少。他们面临的问题是:

可变性:像日期和时间这样的类应该是不可变的

偏移性:Date 中的年份是从 1900 开始的,而月份都从 0 开始

格式化:格式化只对 Date 有用,Calendar 则不行

此外,它们的线程也不是安全的

1
2
3
4
5
6
7
8
9
10
11
import org.junit.Test;
import java.util.Date;

public class MyTest {
@Test
public void test() {
//我们想获取时间2002-3-20,用JDK8之前的方法,不可以直接得到,存在偏移量
Date date = new Date(2022 - 1900,3 - 1,20);
System.out.println(date);
}
}

因此为了更高效的获取时间信息,JDK 8 及之后设置了新的日期时间 API:java . time

java.time.LocalDate/LocalTime/LocalDateTime
LocalDateTime 相较于 LocalDate 和 LocalTime ,使用频率更高

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
import org.junit.Test;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;

public class MyTest {
@Test
public void test() {
LocalDate ld = LocalDate.now();//获取当前日期
LocalTime lt = LocalTime.now();//获取当前时间
LocalDateTime ldt = LocalDateTime.now();//获取当前日期和时间
System.out.println(ld);
System.out.println(lt);
System.out.println(ldt);
//设置年、月、日、时、分、秒,没有偏移量
LocalDateTime ldt1 = LocalDateTime.of(2022,3,20,6,45);
System.out.println(ldt1);
//getXxx()
System.out.println(ld.getDayOfWeek());
//不可变性
LocalDate ld1 = ld.withDayOfMonth(22);
System.out.println(ld);//当前时间
System.out.println(ld1);//更改后时间
}
}

Instant

java.time.Instant

Instant 时间线上的瞬时点。这可能被用来记录应用程序中的事件时间戳

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import org.junit.Test;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;

public class MyTest {
@Test
public void test() {
//now():获取本初子午线对应的标准时间
Instant instant = Instant.now();
System.out.println(instant);
//添加时间偏移量
OffsetDateTime odf = instant.atOffset(ZoneOffset.ofHours(8));
System.out.println(odf);
//获取自1970年1月1日0时0分0秒(UTC)开始的毫秒数
long milli = instant.toEpochMilli();
System.out.println(milli);
//给定毫秒数,获取 Instant 实例
Instant instant1 = Instant.ofEpochMilli(1648977151854L);
System.out.println(instant1);
}
}

DateTimeFormatter

java.time.format.DateTimeFormatter

可以格式化和解析日期与时间

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
import org.junit.Test;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;

public class MyTest {
@Test
public void test() {
//方式一:预定义的标准格式
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//格式化:日期 --> 字符串
LocalDateTime localDateTime = LocalDateTime.now();
String str1 = formatter.format(localDateTime);
System.out.println(str1);
//解析:字符串 --> 日期
TemporalAccessor parse = formatter.parse("2022-04-03T17:21:33.470");
System.out.println(parse);
//方式二:本地化相关的格式
DateTimeFormatter formatter1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
//格式化
String str2 = formatter1.format(localDateTime);
System.out.println(str2);
//方式三:自定义的格式
DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
//格式化
String str3 = formatter2.format(LocalDateTime.now());
System.out.println(str3);
}
}

递归

递归的概述

递归的概述

  • 生活中的递归: 放羊–赚钱–盖房子–娶媳妇–生娃–放羊–赚钱–盖房子–娶媳妇–生娃–放羊…
  • 程序中的递归: 指在当前方法内调用自己的这种现象。
  • 递归的注意事项:
    • 递归要有出口(结束方法),否则会报栈内存溢出错误StackOverflowError
    • 递归的出口不能太晚了

案例演示

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 Test {
static int count = 0;
public static void main(String[] args) {
/*
程序中的递归: 指在当前方法内调用自己的这种现象
注意事项:
1.递归一定要有出口,否则会报栈内存溢出错误StackOverflowError
2.递归出口太晚了,还是会报栈内存溢出错误StackOverflowError
解决办法:合理递归
*/
method();
}

public static void method(){
count++;
if (count == 70000){
return;
}
System.out.println("method 方法执行了...");
method();
}
}

递归累和

需求

  • 计算1 ~ n的累加和

分析

  • num的累加和 = num + (num-1)的累和,所以可以把累加和的操作定义成一个方法,递归调用。

实现

代码实现

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
public class Test1 {
public static void main(String[] args) {
/*
练习一:使用递归计算1 ~ n的和
分析:
1 的累加和 = 1 1的累加和=1
2 的累加和 = 1 + 2 2的累加和=2+1的累加和
3 的累加和 = 1 + 2 + 3 3的累加和=3+2的累加和
4 的累加和 = 1 + 2 + 3 + 4 4的累加和=4+3的累加和
.....
n 的累加和 n的累加和=n+(n-1)的累加和
*/
// 调用getSum方法计算5的累加和
int sum = getSum(5);
System.out.println("5的累加和:"+sum);// 15
}

/**
* 计算一个数的累加和
* @param n
* @return
*/
public static int getSum(int n){
// 出口
if(n == 1){
return 1;
}
return n + getSum(n-1);// 规律
}
}

代码执行图解

image-20230927190518776

递归求阶乘

需求

  • 计算n的阶乘

分析

  • 阶乘:所有小于及等于该数的正整数的积。
1
n的阶乘:n! = n * (n-1) *...* 3 * 2 * 1 

n的阶乘 = n * (n1)的阶乘,所以可以把阶乘的操作定义成一个方法,递归调用。

1
推理得出:n! = n * (n-1)!

实现

代码实现

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
public class Test2 {
public static void main(String[] args) {
/*
递归求阶乘:
规律:
1! = 1 1的阶乘 : 1
2! = 2 * 1 2的阶乘 : 2 * 1的阶乘
3! = 3 * 2 * 1 3的阶乘 : 3 * 2的阶乘
4! = 4 * 3 * 2 * 1 4的阶乘 : 4 * 3的阶乘
5! = 5 * 4 * 3 * 2 * 1 5的阶乘 : 5 * 4的阶乘
....
num! = num * (num-1) * (num-2) *...* 1 num的阶乘 : num * num-1的阶乘
*/
int res = jieCheng(5);
System.out.println("5的阶乘:"+res);// 5的阶乘:120
}

/**
* 计算一个数的阶乘
* @param num
* @return
*/
public static int jieCheng(int num){
// 出口
if (num == 1){
return 1;
}
return num * jieCheng(num-1); // 计算阶乘的规律
}
}

Arrays操作数组

为什么用Arrays

之前学了哪些复制,反转,二分查找,排序等,实际上是要你记住实现的思想,实际开发中我们使用Arrays工具类操作数组。

怎么用

image-20230927203449637

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 $_03_工具类Arrays {

public static void main(String[] args) {
// 1 boolean equals(int[] a,int[] b) 判断两个数组是否相等。
int[] arr1 = new int[]{1,2,3,4};
int[] arr2 = new int[]{1,3,2,4};
boolean isEquals = Arrays.equals(arr1, arr2);
System.out.println("isEquals = " + isEquals);

// 2 String toString(int[] a) 输出数组信息。
String str = Arrays.toString(arr1);
System.out.println("str = " + str);

// 3 void fill(int[] a,int val) 将指定值填充到数组之中。
Arrays.fill(arr1,10);
System.out.println(Arrays.toString(arr1));

// 4 void sort(int[] a) 对数组进行排序。
Arrays.sort(arr2);
System.out.println(Arrays.toString(arr2));

// 5 int binarySearch(int[] a,int key) 对排序后的数组进行二分法检索指定的值。
int[] arr = new int[]{-99, -54, -2, 0, 2, 33, 43, 256, 999};
int index = Arrays.binarySearch(arr, 210);
System.out.println("index = " + index); // 没找到,返回负数
}

}

枚举

1.简介

1.一个类的实例是有限且固定的,这个类称为枚举类。比如季节类,只有四个对象(春、夏、秋、冬)

2.手动实现一个枚举类

(1)通过private将构造器隐藏起来
(2)把这个类的所有可能实例都使用private static final修饰的类变量来保存。
(3)如果有必要,可以提供一些静态方法。

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

public class Season {
private final String name;
private final String desc;
private Season(String name, String desc){
this.name = name;
this.desc = desc;
}
public static final Season SPRING = new Season("春天","踏青");
public static final Season SUMMER = new Season("夏天","夏日炎炎");
public static final Season FAIL = new Season("秋天","秋高气爽");
public static final Season WINTER = new Season("冬天","白雪皑皑");

public String getName(){
return this.name;
}
public String getDesc(){
return this.desc;
}
}
1
2
3
4
5
6
7
8
9
10
package cn.it.lsl;

public class SeasonTest {
public SeasonTest(Season s){
System.out.println(s.getName() + "," + s.getDesc());
}
public static void main(String[] args) {
new SeasonTest(Season.FAIL);
}
}

Season类是一个不可变类。Season类中包含了4个static final常量的Field,这4个常量Field就代表了该类所能创建的对象。当程序需要调用Season对象时,就可以通过Season.SPRING的方式来取得Season对象。

这里顺便复习一下不可变类
不可变类:创建该类的实例后,该实例的Field是不可改变的。
如果要创建自定义的不可变类,需遵循如下规则:
(1)使用private和final修饰符来修饰该类的Field。
(2)提供带参数的构造函数,用于根据传入参数来初始化类里的Field。
(3)仅为该类的Field提供getter方法,不要为该类的Field提供setter方法。
(4)如果有必要,重写Object类的hashCode和equals方法。

3.枚举类

(1)使用enum关键字定义枚举类。枚举类一样可以有自己的Field、方法,可以实现一个或多个接口,也可以有自己的构造器。
(2)使用eunm定义的枚举类默认继承了java.lang.Enum类,而不是继承Object类。
(3)使用enum定义、非抽象的枚举类默认会使用final修饰,因此枚举类不能派送子类。(并不是所有的枚举类都使用final修饰,如抽象枚举类)
(4)枚举类所有实例必须在枚举类的第一行显示列出,否则这个枚举类永远不能产生实例。
(5)所有枚举类都提供一个values方法,该方法可以方便地遍历所有枚举值。

1
2
3
4
5
package cn.lsl;

public enum SeasonEnum {
SPRING,SUMMER,FALL,WINTER;
}
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
package cn.lsl;

public class EnumTest {

public void judge(SeasonEnum s){
switch(s){
case SPRING:
System.out.println("春天");
break;
case SUMMER:
System.out.println("夏天");
break;
case FALL:
System.out.println("秋天");
break;
case WINTER:
System.out.println("冬天");
break;
}
}
public static void main(String[] args) {
//列出所有枚举类的实例
for(SeasonEnum s : SeasonEnum.values()){
System.out.println(s);
}

new EnumTest().judge(SeasonEnum.FALL);
}
}

4.枚举类的Field、方法

枚举类可以定义自己的Field和方法。

1
2
3
4
5
6
package cn.lsl;

public enum Gender {
MALE,FEMALE;
public String name;
}
1
2
3
4
5
6
7
8
9
10
package cn.lsl;

public class GenderTest {
public static void main(String[] args) {
//通过Enum的valueOf方法来获取指定枚举类的枚举值
Gender g = Enum.valueOf(Gender.class, "FEMALE");
g.name = "女";
System.out.println(g + "," + g.name);
}
}

在上面程序中产生Gender对象的方式与普通类不同,而是采用通过Enum的valueOf方法来获取指定枚举类的枚举值,枚举类的实例只能是枚举值,而不是随意通过new来创建的。

其实上面程序中,没有实现java的良好封装,因为name的访问权限是public,这样就会出现随意对name赋值的情况,应该通过方法来控制对name的访问。

改造上面的程序

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
package cn.lsl;

public enum Gender {
MALE,FEMALE;
public String name;
public void setName(String name){
switch(this){
case MALE:
if(name.equals("男")){
this.name = name;
}else{
System.out.println("参数错误");
return;
}
break;
case FEMALE:
if(name.equals("女")){
this.name = name;
}else{
System.out.println("参数错误");
return;
}
break;
}
}
public String getName(){
return this.name;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
package cn.lsl;

public class GenderTest {
public static void main(String[] args) {
//通过Enum的valueOf方法来获取指定枚举类的枚举值
Gender g = Enum.valueOf(Gender.class, "FEMALE");
g.setName("女");
System.out.println(g + "," + g.getName());
g.setName("男");
System.out.println(g + "," + g.getName());
}
}

定义枚举类,以上的做法还是做的不够好,枚举类通常应该设计不可变类。其Field值不应该允许改变,这样会更安全。

所以枚举类的Field都应该使用private final修饰。

1
2
3
4
5
6
7
8
9
10
11
12
package cn.lsl;

public enum Gender {
MALE("男"),FEMALE("女");
private final String name;
private Gender(String name){
this.name = name;
}
public String getName(){
return this.name;
}
}

5.实现接口的枚举类

枚举类可以实现一个或多个接口。

1
2
3
4
5
package cn.it.lsl;

public interface GenderDesc {
void info();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package cn.it.lsl;

public enum Gender implements GenderDesc{
MALE("男"),FEMALE("女");
private final String name;
private Gender(String name){
this.name = name;
}

public String getName(){
return this.name;
}

@Override
public void info() {
// TODO Auto-generated method stub
System.out.println("枚举类实现接口");
}

}

以上在枚举类里面实现接口的方法时,每个枚举值在调用该方法的时候都会有相同的行为(即方法体相同)。
如果需要每个枚举值在调用该方法时表现出不同的行为方式,应该让每个枚举值分别实现该方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package cn.it.lsl;

public enum Gender implements GenderDesc{
MALE("男"){
public void info() {
// TODO Auto-generated method stub
System.out.println("枚举类实现接口,男");
}
},
FEMALE("女"){
public void info() {
// TODO Auto-generated method stub
System.out.println("枚举类实现接口,女");
}
};
private final String name;
private Gender(String name){
this.name = name;
}

public String getName(){
return this.name;
}
}

6.包含抽象方法的枚举类

在枚举类中定义抽象方法的时候不能使用abstract关键字将枚举类定义成抽象类(因为系统会自动为它添加abstract关键字),因为枚举类需要显示创建枚举值,而不是作为父类,所以定义每个枚举值时必须为抽象方法提供实现。

以下一个程序在枚举类中定义了一个抽象方法,这个抽象方法由不同的枚举值提供不同的实现

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
package cn.it.lsl;

public enum Operation {
PLUS{
@Override
public double eval(double x, double y) {
// TODO Auto-generated method stub
return x + y;
}
},
MINUS{
@Override
public double eval(double x, double y) {
// TODO Auto-generated method stub
return x - y;
}
},
TIMES{
@Override
public double eval(double x, double y) {
// TODO Auto-generated method stub
return x * y;
}
},
DIVIDE{
@Override
public double eval(double x, double y) {
// TODO Auto-generated method stub
return x / y;
}
};
public abstract double eval(double x, double y);


public static void main(String[] args) {
System.out.println(Operation.PLUS.eval(2, 3));
System.out.println(Operation.MINUS.eval(2, 3));
System.out.println(Operation.TIMES.eval(2, 3));
System.out.println(Operation.DIVIDE.eval(2, 3));
}
}