文章目录
Java的方法
学习目标
方法是什么?
- 方法是一种语法结构,它可以把一段代码封装成一个功能,以方便重复调用。
使用方法的好处是?
- 提高了代码的复用性。
- 让程序的逻辑更清晰。
关于方法我们应该学会什么?
- 怎么定义方法: 方法有很多不同形式的写法,我们需要掌握在不同的业务场景下写出合适的方法形式
- 怎么调用方法: 方法定义出来是拿来调用的,只能调用才能让方法跑起来
- 方法的内存图: 方法在内存中具体是怎么去工作的
- 方法的参数传递机制: 方法的参数传递原理是什么样的,需要注意什么问题(面试热点)
- 方法其他常见形式、技术: 方法在开发中常见的开发形式:方法重载和方法递归
方法定义和调用
1.方法完整的定义形式、调用
方法定义的完整格式如下:
修饰符 返回值类型 方法名( 形参列表 ){
方法体代码(需要执行的功能代码)
return 返回值;
}
示例:定义一个方法对2个整数求和并返回
// 修饰符: public static
// 返回值类型: int
// 方法名: sum
// 参数列表: int num1, int num2(形参列表可以没有, 可以有很多)
public static int sum(int num1, int num2) {
// 方法执行的代码
int result = num1 + num2;
// 方法的返回值
return result;
}
方法的调用:
- 方法必须调用才可以跑起来,调用格式:
方法名(…);
public static void main(String[] args) {
// 调用sum返回结果
int res1 = sum(10, 20);
int res2 = sum(30, 40);
// 输出函数的返回结果
System.out.println(res1);
System.out.println(res2);
}
public static int sum(int num1, int num2) {
int result = num1 + num2;
return result;
}
使用方法的注意点:
-
方法的修饰符:暂时都使用public static 修饰。
-
方法申明了具体的返回值类型,内部必须使用return返回对应类型的数据。
-
形参列表可以有多个,甚至可以没有; 如果有多个形参,多个形参必须用“,”隔开,且不能给初始化值。
定义一个方法真正需要关注的就两点:1、分析方法是否需要申明返回值类型;2、分析方法是否需要接收参数。
2.方法的其他定义形式、调用
方法的其他写法:
- 方法定义时:返回值类型、形参列表可以按照需求进行填写
注意事项:
-
如果方法不需要返回结果,返回值类型必须申明成void(无返回值), 此时方法内部不可以使用return返回数据。
-
方法如果没有参数,或者没有返回值类型申明为void可以称为无参数、无返回值的方法,依次类推。
示例: 打印三次hello world, 无需参数和返回值
public static void main(String[] args) {
// 调用hello
hello()
}
// 无返回值, 返回值类型声明成void
public static void hello() {
System.out.println("Hello World");
System.out.println("Hello World");
System.out.println("Hello World");
}
3.方法常见问题
方法的编写顺序无所谓。
- 定义的方法在main方法的上面和下面都是可以的
方法与方法之间是平级关系,不能嵌套定义。
- 例如: main方法中是无法在定义方法的
方法的返回值类型为void(无返回值),方法内则不能使用return返回数据,如果方法的返回值类型写了具体类型,方法内部则必须使用return必须返回对应类型的数据。
return语句下面,不能编写代码,因为永远执行不到,属于无效的代码。
方法不调用就不执行, 调用时必须严格匹配方法的参数情况。
有返回值的方法调用时可以选择定义变量接收结果,或者直接输出调用,甚至直接调用;无返回值方法的调用只能直接调用。
方法的案例
学完方法的基本使用, 可以写几个案例来练习方法的使用
1.计算1-n的和返回
需求:定义一个方法,方法中计算出 1-n (包含n)的和并返回
分析:
-
根据格式编写方法 —-> 因n不固定,故方法需要声明形参接收;要返回结果,还需申明返回值类型。
-
方法内部使用 for 循环计算出 1-n 的和并返回。
演示代码:
public static void main(String[] args) {
// 传入n为5
System.out.println(sum(5));
}
public static int sum(int n) {
int result = 0;
for (int i = 1; i <= n; i++) {
result += i;
}
return result;
}
2.判断整数是奇数还是偶数
需求:传入一个整数,然后调用方法,把整数交给方法,在方法中输出该数为奇数还是偶数
分析:
-
根据格式编写方法 —-> 因要传入数据给方法,方法需要声明形参接收。
-
方法内部使用if语句判断,并输出对应的结论。
public static void main(String[] args) {
// 调用check, 传入参数为6
check(6) // 6是一个偶数
// 调用check, 传入参数为3
check(3) // 3是一个奇数
}
// 无需返回值, 将返回值类型定义为void
public static void check(int n) {
if (n / 2 == 0) {
System.out.println(n + "是一个奇数");
} else {
System.out.println(n + "是一个偶数");
}
}
3.数组求最值改方法实现
需求:定义一个方法, 传入一个数组给方法, 方法返回数组的最大值。
分析:
- 根据格式编写方法: 要返回最大值,需要申明返回值类型; 需要接收数组, 需要申明形参列表。
- 方法内部找出数组的最大值并返回。
public static void main(String[] args) {
int[] nums = {25, 26, 10, 30, 1, 60};
System.out.println(arrMax(nums)); // 60
}
public static int arrMax(int[] arr) {
int max = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
方法调用的内存图
方法没有被调用的时候,在方法区中的字节码文件中存放
方法被调用的时候,需要进入到栈内存中运行
1.调用流程 – 内存图解(一)
- 下面代码时如何执行的呢
public class Test {
public static void main(String[] args) {
int sum = add(10, 20);
System.out.println(sum);
}
public static int add(int a, int b ){
int c = a + b;
return c;
}
}
- 代码会先执行main方法, 首先main方法会进入栈内存
- 执行main方法时, 执行到
int sum = add(10, 20);
时, 发现main方法中又调用了add方法, - 那么会先去执行add方法, add方法也会进入栈内存开始执行
- 当add方法执行完成后, 此时c的值已经是30, add方法就会弹出栈内存
- add方法弹出栈内存后, 会继续执行main方法的输出语句:
System.out.println(sum);
- main方法执行完成后同样会弹出栈内存
- 此时我们程序也已经全部运行完成
2.调用流程 – 内存图解(二)
- 我们继续看看下面稍微复杂一点的代码, 它的执行流程是怎样的
- 输出结果的顺序是: 吃饭, 学习, 睡觉
public class Demo2Method {
public static void main(String[] args) {
study();
}
public static void sleep(){
System.out.println("睡觉");
}
public static void eat(){
System.out.println("吃饭");
}
public static void study(){
eat();
System.out.println("学习");
sleep();
}
}
- 方法区会有四个方法: 分别是main , study , sleep , eat
- 首先我们会执行main方法, main方法进入栈内存执行, 执行main方法的
study();
语句时, 会调用study方法 - 那么study方法会进入栈内存中执行, 执行study方法的
eat();
语句时, 会调用eat方法 - eat方法又会进入到栈内存中执行, 执行
System.out.println("吃饭");
方法, 输出吃饭
- eat方法执行完成后, 会弹出栈内存
- 继续执行study方法的
System.out.println("学习");
语句, 输出学习
- 继续执行study的
sleep();
语句, 那么就会调用sleep方法 - sleep方法进入栈内存, 并且执行
System.out.println("睡觉");
语句, 输出睡觉
- sleep执行完成, sleep方法弹出栈内存
- 此时study同样也执行完成, stud方法弹出栈内存
- study执行完成的话, main方法也执行完成, main方法也弹出栈内存
- 此时代码全部执行完毕, 栈内存也已经清空
方法参数传递机制
1.值传递
Java中基本类型的参数传递机制:值传递
- 在传输实参给方法的形参的时候,并不是传输实参变量本身, 而是传输实参变量中存储的值,这就是值传递。
比如下面代码中, 我们是将a的值: 10, 传给了change方法, 并不是直接将a这个变量传给了change方法
public class Test {
public static void main(String[] args) {
int a = 10;
change(a);
}
public static void change(int c){
}
}
可能这样说起来还是比较抽象, 我们通过一个面试题, 并画图给大家解释:
- 理解下面三个地方的
System.out.println(a);
语句分别输出什么
public class Test {
public static void main(String[] args) {
int a = 10;
change(a);
System.out.println(a); // 10
}
public static void change(int a){
System.out.println(a); // 10
a = 20;
System.out.println(a); // 20
}
}
- 方法区中两个方法: main方法和change方法
- main方法进入栈内存中先执行
- 执行到main方法的
change(a)
语句时, change方法会进入栈内存中执行 - 同时, 会将
a = 10
的值10传给change方法中的a, 那么change方法中的a的值也保存的是10 - 执行change方法的第一条
System.out.println(a);
语句, 输出10
- 输出完成后, 执行change方法中的
a = 20;
语句, 此时change方法中的a会改变成20 - 然后执行change方法的第二条
System.out.println(a);
语句, 输出为20
- change方法执行完成, 弹出栈内存
- 回到main方法, 继续执行main方法的
System.out.println(a);
语句 - main方法的a并没有改变, 输出结果依然为10
2.引用传递
Java中引用类型的参数传递机制:引用传递
- 引用传递, 传递的是变量名中保存的地址 , 这就是引用传递
我们同样通过一个例子, 画图给大家分析什么是引用传递:
- 这个例子和刚刚的类似, 只不过传递的值是一个数组
public class Test {
public static void main(String[] args) {
int[] arrs = new int[]{10, 20, 30};
change(arrs);
System.out.println(arrs[1]); // 222
}
public static void change(int[] arrs){
System.out.println("方法内部2:"+arrs[1]); // 20
arrs[1] = 222;
System.out.println("方法内部2:"+arrs[1]); // 222
}
}
- 方法区中有两个方法: main和change
- main方法先进去栈内存中, 执行
int[] arrs = new int[]{10, 20, 30};
语句 - 执行这一语句, 会在堆内存中开辟一个空间保存数组, 并将这个空间的地址赋值给arrs这个变量
- 继续执行
change(arrs);
语句, 此时change方法进入栈内存执行 - 同时将main方法的arrs这个变量的地址, 传给change方法的arrs
- 然后继续执行change方法的第一个
System.out.println("方法内部2:"+arrs[1]);
语句, 输出20
- 继续执行change方法
arrs[1] = 222;
语句, 通过地址找到数组, 将数组第二个元素修改为222 - 执行第二个
System.out.println("方法内部2:"+arrs[1]);
语句, 输出结果为222
- change方法执行完成, 弹出栈内存
- 继续执行main方法的
System.out.println(arrs[1]);
语句 - main方法同样根据地址去找数组, 由于和change方法的地址一样, 所以找到的数组也是同一个, 此时数组的第二个元素已经被修改, 那么main方法的输出数组第二个元素应该为222
方法参数传递案例
1.打印整型数组内容
需求:
- 设计一个方法用于输出任意整型数组的内容,要求输出成如下格式:
- “该数组内容为:[11, 22, 33, 44, 55]”
分析:
- 定义一个方法,要求该方法能够接收数组,并输出数组内容。 —> 需要参数吗?需要返回值类型申明吗?
- 定义一个静态初始化的数组,调用该方法,并传入该数组。
示例代码:
public class methodDemo03 {
public static void main(String[] args) {
int[] nums = {10, 20, 66, 88, 99};
showArr(nums);
}
public static void showArr(int[] arr) {
System.out.print("该数组的内容为: [");
if (arr.length > 0 && arr != null) {
for (int i = 0; i < arr.length; i++) {
System.out.print(i == arr.length - 1? arr[i]: arr[i] + ", ");
}
}
System.out.println("]");
}
}
2.查询数组元素索引
需求:
- 设计一个方法可以接收整型数组,和要查询的元素值;最终要返回元素在该数组中的索引,如果数组中不存在该元素则返回 -1。
分析:
- 定义方法,接收整型数组,查询的元素值,在方法体中完成元素查询的功能。—> 是否需要参数、返回值类型?
- 定义数组,调用该方法,并指定要搜索的元素值,得到返回的结果输出。
示例代码:
public class methodDemo04 {
public static void main(String[] args) {
int[] nums = {10, 30, 66, 88, 99};
System.out.println(queryIndex(nums, 88)); // 3
}
public static int queryIndex(int[] arr, int num) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == num) return i;
}
return -1;
}
}
3.比较数组是否相同
需求:
- 要求传入两个整形数组, 如果两个数组, 元素个数,元素顺序和内容是一样的我们就认为这2个数组是一模一样的。
- 请使用方法完成:能够判断任意两个整型数组是否一样,并返回true或者false。
分析:
- 定义方法,接收2个整型数组,—> 是否需要参数、返回值类型?
- 在方法内部完成判断的逻辑,并返回布尔结果。
public class methodDemo05 {
public static void main(String[] args) {
int[] arr1 = {10, 20, 30};
int[] arr2 = {10, 20, 30};
int[] arr3 = {10, 20, 99};
System.out.println(compare(arr1, arr2)); // true
System.out.println(compare(arr1, arr3)); // false
}
public static boolean compare(int[] arr1, int[] arr2) {
if (arr1.length != arr2.length) return false;
for (int i = 0; i < arr1.length; i++) {
if (arr1[i] != arr2[i]) return false;
}
return true;
}
}
方法重载
方法重载: 同一个类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法就是重载方法。
我们结合案例来理解一下方法重载 :
例如开发武器系统,功能需求如下:
- 可以默认发一枚武器。
- 可以指定地区发射一枚武器。
- 可以指定地区发射多枚武器。
示例代码 :
// 1.默认给岛国发射一枚导弹
public static void fire() {
System.out.println("给岛国的随机地区发射1枚导弹给岛国");
}
// 2.给岛国指定地区发射一枚导弹
public static void fire(String address) {
System.out.println("给岛国的" + address + "地区发射1枚导弹");
}
// 3.给岛国指定地区发射自定义枚导弹
public static void fire(String address, int num) {
System.out.println("给岛国的" + address + "地区发射" + num + "枚导弹");
}
调用方法的时候, 会通过参数的不同来区分调用的是哪个方法
public static void main(String[] args) {
fire();
fire("东京");
fire("东京", 9999);
}
方法重载还有另一种使用方法: 效果一样的, 代码更简洁
public static void main(String[] args) {
fire();
fire("东京");
fire("东京", 9999);
}
// 1.默认给岛国发射一枚导弹
public static void fire() {
// 可以方法中调用方法, 效果一样使代码更简洁
fire("随机");
}
// 2.给岛国指定地区发射一枚导弹
public static void fire(String address) {
fire(address, 1);
}
// 3.给岛国指定地区发射自定义枚导弹
public static void fire(String address, int num) {
System.out.println("给岛国的" + address + "地区发射" + num + "枚导弹");
}
方法重载的好处: 对于相似功能的业务场景:可读性好,方法名称相同提示是同一类型的功能,通过形参不同实现功能差异化的选择,这是一种专业的代码设计。
方法重载的识别:
-
只要是同一个类中,方法名称相同、形参列表不同,那么他们就是重载的方法,其他都不管!(如:修饰符,返回值类型都无所谓)
-
形参列表不同指的是:形参的个数、类型、顺序不同,不关心形参的名称
return的单独使用
return关键字单独使用
return;
—> 可以立即跳出并结束当前方法的执行; return关键字单独使用可以放在任何方法中。
public class Test {
public static void main(String[] args) {
System.out.println("开始");
chu(10 , 0);
System.out.println("结束");
}
public static void chu(int a , int b){
if(b == 0){
System.err.println("您的数据有误!!不执行!!");
return; // 直接结束当前方法chu
}
int c = a / b;
System.out.println("除法结果是:"+c);
}
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/120100.html