重载、参数传递、可变参数、循环嵌套、递归

第1章 方法重载OverLoad

1.2 概念

  • 方法重载:指在同一个类中,允许存在一个以上的同名方法,只要它们的参数列表不同即可,与修饰符和返回值类型无关。
    • 多个方法在同一个类中
    • 多个方法具有相同的方法名
    • 多个方法的参数不相同,类型不同或者数量不同
  • 注意
    • 参数列表:个数不同,数据类型不同,顺序不同
    • 重载方法调用:JVM通过方法的参数列表,调用不同的方法。
  • 使用方法重载完成以上练习
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 Demo02MethodOverLoad {
public static void main(String[] args) {
//调用方法: 输出调用
System.out.println(getSum(10,20));
System.out.println(getSum(10,20,30));
System.out.println(getSum(10.0,20.0));
System.out.println(getSum(10.0,20.0,30.0));

}

//1.定义一个获取两个int数字之和的方法
public static int getSum(int a, int b) {
System.out.println("求两个int数字之和....");
return a + b;
}

//2.定义一个获取三个int数字之和的方法
public static int getSum(int a, int b,int c) {
System.out.println("求三个int数字之和....");
return a + b + c;
}

//3.定义一个获取两个double数字之和的方法
public static double getSum(double a, double b) {
System.out.println("求两个double数字之和....");
return a + b;
}

//4.定义一个获取三个double数字之和的方法
public static double getSum(double a, double b,double c) {
System.out.println("求三个double数字之和....");
return a + b + c;
}
}

1.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
/*
参数列表不同有哪些情况,可以构成重载?
1.参数的数量不同
2.参数的类型不同
3.多个类型顺序不同

方法重载关键看: 在方法名称相同的前提下,参数列表必须要有本质(名称不算)的区别
*/
1.定义方法method,没有参数
public static void method() {}
2.定义方法method,有一个int参数
//1没有参数,2有一个参数,参数的数量不同,可以构成重载
public static void method(int a) {}
3.定义方法method,有一个double参数
//2有一个int参数,3有一个double参数,参数的类型不同,可以构成重载
public static void method(double a) {}
4.定义方法method,有一个int参数和一个double参数
public static void method(int a, double b) {}
5.定义方法method,有一个double参数和一个int参数
//4是先int后double,5是先double后int,多个类型顺序不同
public static void method(double a, int b) {}


//1.定义方法method,参数是一个int,一个double
public static int method(int a, double b) {
return 0;
}
//2.定义方法method,参数是一个int,一个double
//1返回int类型,2返回double类型,其它没有区别,不能构成重载,因为方法重载与返回值类型无关
public static double method(int a, double b) {
return 0.0;
}

//3.定义方法method,参数是一个int,一个double
//1.的参数名称叫a和b,3的参数名称叫c和d,其它没有却别,不能构成重载因为方法重载与参数名称无关
public static int method(int c, double d) {
return 0;
}

//4.定义方法method,参数是一个int,一个double
//1修饰符是public static,4修饰符是public,其它没区别,不能构成重载因为方法重载与修饰符无关
public int method(int a, double b) {
return 0;
}

// 目标:掌握方法重载的应用场景。
public static void main(String[] args) {
fire();
fire("岛国2");
fire("米国", 999);
}
public static void fire(){
fire("岛国");
}
public static void fire(String country){
fire(country, 1);
}
public static void fire(String country, int number){
System.out.println("发射了" + number + "枚武器给" + country);
}

1.4 方法重载练习

  • 需求:判断哪些方法是重载关系。
1
2
3
4
5
6
7
8
9
public static void open(){}
public static void open(int a){}
static void open(int a,int b){}
public static void open(double a,int b){}
public static void open(int a,double b){}
public void open(int i,double d){}
public static void OPEN(){}
public static void open(int i,int j){}
//都是重载关系

第2章 方法的参数传递

2.1 概念

  • 传递给方法中的参数,这样方法中的参数就拥有了这个指定的值,可以使用该值,在方法中运算了。这种传递方式,我们称为参数传递。
  • 参数列表中的变量,我们称为形式参数
  • 调用方法时,传入给方法的数值,我们称为实际参数

2.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
/*
形式参数:
在定义方法时,()中定义的变量,称为形式参数,定义时必须不能有值,方法被调用时,才会有值实际参数:
在调用方法时,()中给定的参数(常量/变量),称为实际参数,如果是变量,则必须要有值

基本类型作为方法的形式参数
特点:
形式参数的改变,不会影响实际参数
原因:
基本类型作为参数,传递的是具体的数据值
每个方法都有自己的内存空间,所以每个方法内部的变量也有自己的内存空间,即便是不同的方法内部定义了同名的变量,他们的内存空间不同,它们之间互不影响,互不干扰

*/
public class Demo03BaseVar {
public static void main(String[] args) {
int a = 10;
int b = 20;
System.out.println("ms..a="+a);//10
System.out.println("ms..b="+b);//20

//调用方法
change( a, b );//调用方法时,()中给出的参数,称为实际参数

System.out.println("me..a="+a);//10
System.out.println("me..b="+b);//20
}

//定义方法
public static void change(int a, int b) {//方法定义时,()中定义的变量,称为形式参数
System.out.println("cs..a="+a);//10
System.out.println("cs..b="+b);//20
a = a * 10;
b = b * 10;
System.out.println("ce..a="+a);//100
System.out.println("ce..b="+b);//200

return ;//结束方法,返回到调用处
}
}

注意:形式参数的改变不影响实际参数

1603598347114

2.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
/*
引用类型作为方法的形式参数
特点:
形式参数的改变,会影响实际参数
通过形参找到堆内存空间的数组,修改元素值后,再通过实参看到的是修改后的数组内容

原因:
引用变量保存的是堆内存空间的地址值,调用方法传递的是地址值,
导致多个变量指向同一个数组,只要有一个变量修改的数组的元素,
其它变量看到的都是修改后的元素
*/
public class Demo04RefVar {
public static void main(String[] args) {
int[] a = new int[] {10,20};//数组变量a保存数组在堆内存空间的地址
System.out.println("ms..a[0]="+a[0]);//10
System.out.println("ms..a[1]="+a[1]);//20

//调用方法: 传递的是地址值
change( a );//调用方法时,()中给出的参数,称为实际参数

System.out.println("me..a[0]="+a[0]);//100
System.out.println("me..a[1]="+a[1]);//200
}

//定义方法
public static void change(int[] a) {//方法定义时,()中定义的变量,称为形式参数

System.out.println("cs..a[0]="+a[0]);//10
System.out.println("cs..a[1]="+a[1]);//20
a[0] = a[0] * 10;
a[1] = a[1] * 10;
System.out.println("ce..a[0]="+a[0]);//100
System.out.println("ce..a[1]="+a[1]);//200

return ;//结束方法,返回到调用处
}
}

注意:引用类型,作为方法参数,形式参数的改变会影响实际参数

1603598380196

2.6 双色球

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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
package com.zxq._04_双色球;

import java.util.Random;
import java.util.Scanner;

/*
双色球规则:
红色: [1,...33]
蓝色: [1,...16]
每注双色球都由6个红球和1个篮球组成,且不能重复
开奖规则:
奖级 中奖条件(红球 + 蓝球) 奖金类型 单注奖金
一等奖 6 红 + 1 蓝(全中) 浮动奖 当期高等奖 75%+ 奖池,单注最高 1000 万(派奖期可达 2000 万)
二等奖 6 红 + 0 蓝 浮动奖 当期高等奖 25%
三等奖 5 红 + 1 蓝 固定奖 3000 元
四等奖 5 红 + 0 蓝 或 4 红 + 1 蓝 固定奖 200 元
五等奖 4 红 + 0 蓝 或 3 红 + 1 蓝 固定奖 10 元
六等奖 0–2 红 + 1 蓝(蓝球必中) 固定奖 5 元
福运奖(特殊) 3 红 + 0 蓝(奖池≥15 亿时启动) 固定奖 5 元

使用代码,模拟
1: 生成一注双色球
2: 让用户购买一注双色球
3: 判断用户中了几等奖

*/
public class Test04 {
public static void main(String[] args) {
// 调用方法生成双色球
int[] arr = init();
for (int i : arr) {
System.out.print(i+" ");
}
// 调用用户购买双色球的方法
int[] arr2 = userBuy();
System.out.println();
String kj = kj(arr, arr2);
System.out.println(kj);

}
// 开奖的方法,需要调用者,传递生成的双色球是什么?用户购买的双色球是什么?最终返回中奖的结果
public static String kj(int[] system,int[] user){
// 按开奖规则进行开奖
// 判断用户购买的蓝色球是否中了,红色球中了几个,才能根据"个数开奖"
boolean lanRes = system[0] == user[0];
// 定义一个变量,用于统计红色球猜中的个数
int count = 0;
for (int i = 1; i < user.length; i++) {
// 获取用户填写的当前的红色球
int v = user[i];
// 根据v,去 system的1--6索引之间,找,是否存在,如果存在,则让count++
boolean red = findRedByKey(system, 1, system.length, v);
if(red){
count++;
}
}
System.out.println("蓝色球的结果:"+lanRes);
System.out.println("红色球的结果:"+count);
// 判断是否中了 几 等奖
if(lanRes && count == 6){
return "1等奖";
}
if(count == 6){
return "2等奖";
}
if(lanRes && count == 5){
return "3等奖";
}
//四等奖 5 红 + 0 蓝 或 4 红 + 1 蓝
if(count == 5 || (lanRes && count == 4)){
return "4等奖";
}
//五等奖 4 红 + 0 蓝 或 3 红 + 1 蓝 固定奖 10 元
if(count == 4 || (lanRes && count == 3)){
return "5等奖";
}
//六等奖 0–2 红 + 1 蓝(蓝球必中) 固定奖 5 元
if(lanRes){
return "6等奖";
}

return "感谢您为中国福利彩票事业作出了贡献...";
}

// 生成一注双色球
public static int[] init() {
// 为了区分红色球和蓝色球,人为规定,将蓝色球保存到 0 索引位置,1--6索引保存6个红色球
int[] arr = new int[7];
// 随机生成一个 蓝色球: [1,...16]并存入数组的0索引
Random random = new Random();
int randomCode = random.nextInt(1, 17);
arr[0] = randomCode;
// 生成6个不重复的红色球,并保存到数组的1--6索引
for (int i = 1; i < arr.length; ) {
// 随机生成红色球
int h = random.nextInt(1, 34);
// 确保此时的 h 和 1--i索引之间的数字都不一样即可存入数组!!!!
// 为了逻辑好理解,单独设计一个方法,帮我们根据指定的范围和值,查询是否存在!
boolean exists = findRedByKey(arr,1,i,h);
// true代表存在,需要重新生成红色球
if(exists){
continue;
}
arr[i] = h;
i++;
}
return arr;
}

// 这个方法是专门查询指定范围内指定元素是否存在的 ,目的是为了控制生成的红色球一定不一致!
private static boolean findRedByKey(int[] arr, int min, int max, int key) {
for (int i = min; i < max; i++) {
if(arr[i] == key){
return true;
}
}
return false;
}

// 让用户购买一注双色球
public static int[] userBuy(){
Scanner sc = new Scanner(System.in);
int[] arr = new int[7];
// 让用户填写蓝色球
while (true){
System.out.println("亲,请填写要购买的蓝色球号码:");
int lan = sc.nextInt();
if(lan >= 1 && lan <= 16){
arr[0] = lan;
break;
}else {
System.out.println(lan+"不合法,请重新填写[1,16]之间的数字...");
}
}
// 让用户填写6个红色球
for (int i = 1; i < arr.length; ) {
System.out.println("亲,请填写要购买第"+i+"个红色球号码:");
int h = sc.nextInt();
// 对h的合法性进行校验,如果不合法,提示重新输入,如果合法,就进行重复性校验,如果重复了,也需要重新输入!
if(h >= 1 && h <= 33){
// 如果合法,就进行重复性校验,如果重复了,也需要重新输入!
boolean red = findRedByKey(arr, 1, i, h);
if(red){
// 存在,重新输入
System.out.println(h+"重复了,请重新填写[1,33]之间的数字...");
}else {
arr[i] = h;
i++;
}
}else {
System.out.println(h+"不合法,请重新填写[1,33]之间的数字...");
}
}
return arr;
}
}

第3章 可变参数

3.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
32
33
34
35
36
37
38
39
40
可变参数: 可以变化的参数
在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化.

格式:
一定是在定义方法参数时,使用: 数据类型 ... 变量名称
修饰符 返回值类型 方法名称(数据类型 ... 变量名称) {...}

使用:
可变参数的本质就是数组,调用含有可变参数的方法时,
可以传递参数列表,可以传递数组,还可以不传参数

/*
练习可变参数入门
*/
public class Test01 {
public static void main(String[] args) {
method(2,4,6,8,9);
method(2,4);
method(1);
}

/* public static void method(int a){
System.out.println("一个参数的方法..."+a);
}*/
public static void method(int a,int b){
System.out.println("2个参数的方法..."+a+","+b);

}
public static void method(int... a){
System.out.println("可变参数的方法..."+a);
// 本质是数组,直接输出看到的是数组的地址值,如果想操作内容,可以使用遍历的方式操作
for (int i : a) {
System.out.println(i);
}
}

/* public static void method(int[] arr){
System.out.println("可变参数的方法..."+arr);
}*/
}

3.2 注意事项

1
2
3
4
5
6
7
/*
注意事项:
1.可变参数的本质就是数组
2.调用方法时,可以传递参数列表,可以传递数组,还可以不传参数
3.方法参数列表中的可变参数,只能定义在参数列表最后
4.方法参数列表中的可变参数只允许有一个
*/

最后还有一些错误写法

  • **一个形参列表中,只能有一个可变参数 ****;否则会报错**
  • 一个形参列表中**如果多个参数,可变参数需要写在最后;否则会报错**

第4章 循环嵌套

4.1 需求: 打印3行5列的星

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
/*
需求: 打印3行5列的星
循环嵌套:
1.概念: 使用一个循环作为另外一个循环的循环体,外部的循环叫做外层循环,内部的循环叫做内层循环
2.格式:
for(外初始化表达式1;外循环条件2;外步进表达式7){
for(内初始化表达式3;内循环条件4;内步进表达式6){
内循环体5;
}
}
其它语句8;
3.注意:
(1)外层循环初始化表达式 int i = 1 执行了几次? 1次
(2)内层循环初始化表达式 int j = 1 执行了几次? 3次
(3)总结:
外层循环执行1次,内层循环要执行完整的一遍
内层循环的循环体执行的次数:
外层循环执行的次数 * 内层循环每遍执行的次数
*/
public class Demo07ForFor {
public static void main(String[] args) {
//使用for循环优化,打印5个星的代码
for (int i = 1; i <= 3; i++) {//外层循环: 执行3次
for (int j = 1; j <= 5; j++) {//内层循环: 每遍执行5次
System.out.print("*");
}
System.out.println();
}
}
}

4.2标号语句

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Test05 {
public static void main(String[] args) {
abcd:for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= 3; j++) {
if(j==2){
// 我希望在这里的时候,让外层的循环,重新开始下一次
continue abcd;
}
System.out.println("内循环的j="+j);
}
System.out.println("外循环的i="+i);
}
System.out.println("main方法介绍");
}
}

4.3 练习

​ 使用嵌套循环,打印2021年至2023年月份,格式:xxxx年x月

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
1.使用循环嵌套:
打印2021年至2023年月份,格式:xxxx年x月

2.注意:
(1)外层循环初始化表达式 int year = 2021 执行了几次? 1次
(2)内层循环初始化表达式 int month = 1 执行了几次? 3次
(3)总结:
外层循环执行1次,内层循环要执行完整的一遍
内层循环的循环体执行的次数: 3 * 12 = 36
*/
public class Demo08ForForMonth {
public static void main(String[] args) {
for (int year = 2021; year <= 2023; year++) {//外层循环: 获取年份,循环3次
for (int month = 1; month <= 12; month++) {//内层循环: 获取每年的12个月份,每遍执行12次
System.out.println(year + "年" + month + "月");
}
}
}
}

第5章 递归

5.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
方法递归
1.概念: 方法自己调用自己
2.死递归: 永不休止的自己调用自己
public static void method(int num) {
System.out.println(num);
num--;
method(num);
}
3.正常递归: 递归次数不宜过多,可以正常结束
public static void method(int num) {
System.out.println(num);
num--;
if(num == 0) {
return ;
}
method(num);
}

4.注意:
(1)方法在栈内存中执行,栈内存空间有大小限制,所以
方法递归调用次数不宜过多,否则出栈内存溢出

(2)方法的调用是先进后出的特点,上面的方法不弹栈,
下面的方法也不能弹栈,上面的方法不结束,下面的方法也不能结束

(3)要想进行正常的递归操作必须找到递归调用的规律

(4)要想进行正常的递归操作必须找递归调用的出口
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Demo04DiGui {
public static void main(String[] args) {
method(10);
}
public static void method(int num) {
System.out.println(num);
num--;
if(num == 0) {
return ;
}
method(num);
}
}

1602163362381

5.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
/*
递归求1到n的和
假设求1到100的和,并假设定义方法sum(100)
sum(100) = 1 + 2 + 3 + 4 + ...+ 100
sum(100) = 100 + 99 + 98 + 97 + ... + 1

为了找出规律,假设求1到5的和
sum(5) = 5 + 4 + 3 + 2 + 1
= 5 + sum(4)
sum(4) = 4 + 3 + 2 + 1
= 4 + sum(3)
sum(3) = 3 + 2 + 1
= 3 + sum(2)
sum(2) = 2 + sum(1)
sum(1) = 1 出口
注意:
1.找规律
sum(5) = 5 + sum(4) = 5 + sum(5-1)
sum(n) = n + sum(n-1)

2.找出口
sum(1) = 1
if(n == 1){ return 1; }
*/
public class Demo05DiGuiSum {
public static void main(String[] args) {
int result = sum(4);
System.out.println(result);
}

//定义方法,求1到n的数字之和
public static int sum(int n) {
//出口
if (n == 1) {
return 1;
}
//规律
return n + sum(n-1);
}
}

5.3 递归求和图解分析

1602163551221

5.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
/*
遍历 day11_xw\io 目录下的所有文本文件(包含子文件夹)
实现步骤:
1.创建File对象,代表存在的文件目录
2.定义方法printNames方法,作用递归打印文本文件的名字
3.调用printNames方法,传递步骤1中的File对象
*/
public class Demo03EachTxtFiles {
public static void main(String[] args) {
//1.创建File对象,代表存在的文件目录
File dir = new File("day11_xw\\io");
//3.调用printNames方法,传递步骤1中的File对象
printNames(dir);
}

//2.定义方法printNames方法,作用递归打印文本文件的名字
public static void printNames(File dir) {
//(1)获取当前文件夹下的所有文件/子文件夹组成的File对象数组
File[] files = dir.listFiles();
//健壮性判断
if (files != null && files.length > 0) {
//(2)增强for遍历
for (File file : files) {
//(3)如果是文件
if(file.isFile()) {
//是txt文件
if (file.getName().toLowerCase().endsWith(".txt")) {
System.out.println(file.xiaoFeiName());
}
} else {
//(4)是文件夹,递归调用
printNames(file);
}
}
}
}
}

5.5 递归获取文件夹下所有文件图解分析

1602163767252