【JAVA入门】Day04 - 方法
文章目录
- 【JAVA入门】Day04 - 方法
- 一、方法的格式
- 1.1 无参无返回值的方法定义和调用
- 1.2 带参数的方法定义和调用
- 1.3 形参和实参
- 1.4 带返回值的方法定义和调用
- 1.5 方法的注意事项
- 二、方法的重载
- 三、方法的使用
- 四、方法的内存原理
- 4.1 方法调用的基本内存原理
- 4.2 方法传递基本数据类型的内存原理
方法(methond)是程序中最小的执行单元。在编写程序时,我们将重复的代码、具有独立功能的代码抽取到方法中,从而节省大量的代码量,提高代码的复用性、可维护性。
一、方法的格式
把一些代码打包在一起,这个过程叫做方法定义。
方法定义后不是直接运行的,需要手动调用才能执行,这个过程称为方法调用。
1.1 无参无返回值的方法定义和调用
定义格式:
public static void 方法名(){
方法体(打包代码);
}
调用格式:
方法名();
1.2 带参数的方法定义和调用
定义格式:
public static void 方法名(参数1, 参数2, ...){
方法体(打包代码);
}
调用格式:
方法名(参数1, 参数2, ...);
注意:在传递参数时,参数的数据类型也要和定义时的数据类型一一对应。
1.3 形参和实参
形参就是形式参数,即方法定义中的参数。
实参就是实际参数,即方法调用中的参数。
public static void main(String[] args) {
getSum(10, 20);
}
public static void getSum(int num1, int num2) {
System.out.println(num1 + num2);
}
以上方的代码为例,10 20 是实参,num1 num2 是形参,它们的数据类型需要一一对应。
【例1】求出⚪的面积。
需求:定义一个方法,求圆的面积,将结果打印于方法。
public static void main(String[] args) {
getArea(1.5);
}
public static void getArea(double r) {
double pi = 3.1415926;
double area = pi*r*r;
System.out.println(area);
}
1.4 带返回值的方法定义和调用
带返回值的方法在执行完毕后,可以将最终运行结果返回。为了在调用处拿到方法产生的结果,就需要定义带有返回值的方法。
定义格式:
public static 返回值类型 方法名(参数1, 参数2, ...){
方法体(打包代码);
return 返回值;
}
注意:有返回值的函数需要指定返回值类型(类型不为 void),并且函数体内一定要有 return 语句,用于返回值的返回。
例:
public static int getSum(int a, int b) {
int c = a + b;
return c;
}
调用格式:
- 直接调用:
方法名(实参);
直接调用的方法是不接收返回值,而是单纯执行这个方法。
- 赋值调用:
变量类型 变量名 = 方法名(实参);
赋值调用是用一个变量接收返回值并存储下来留作备用。
- 输出调用:
System.out.println(方法名(实参));
输出调用是将方法的运行结果直接放到打印语句中,这样可以直接打印在控制台。
【例2】定义方法,比较两个长方形的面积。
public static void main(String[] args) {
double rec1,rec2;
rec1 = getArea(1,2);
rec2 = getArea(3,4);
if(rec1 > rec2) {
System.out.println("rec1面积大");
}
else if(rec1 == rec2) {
System.out.println("两个面积一样大");
}
else {
System.out.println("rec2面积大");
}
}
public static int getArea(double w, double h) {
double area = w*h;
return area;
}
以上就是一个方法体完整的定义和调用格式。
1.5 方法的注意事项
- 方法不调用就不会执行
- 方法与方法之间是平级关系,不能互相嵌套定义,但可以嵌套调用。
- 方法的编写顺序与运行顺序无关。
- 如果一个方法的返回值类型写的是 void,则表示该方法没有返回值,其 return 语句可以省略不写,如果要写,直接写作:
return;
- return 语句下面编写的代码,永远执行不到,属于无效代码。
二、方法的重载
在同一个类中,定义了多个同名的方法,这些同名的方法具有同种的功能。
每个方法具有不同的参数类型或参数个数,这些同名的方法,构成了一种重载的关系。
因此,在同一个类中,方法名相同,参数不同的方法(与返回值无关),叫做重载方法。其中,参数不同可能包括:个数不同、类型不同、顺序不同。
【例1】求和。
public class MethodDemo {
public static int sum(int a, int b) {
return a + b;
}
public static int sum(int a, int b, int c) {
return a + b + c;
}
}
以上两个方法在同一个类里,且方法名相同,参数不同,所以构成重载。
【例2】返回值无关。
public class MethodDemo {
public static void fn(int a) {
//方法体
}
public static int fn(int a) {
//方法体
}
以上两个方法纵使返回值不同,但是它们名字相同,参数也相同,所以不构成重载。
public class MethodDemo {
public static float fn(int a) {
//方法体
}
public static int fn(int a, int b) {
//方法体
}
以上两个方法返回值不同,那无所谓,只因为它们名字相同,参数也相同,所以构成重载。
【例3】不在同一个类里的两个同名函数,也不构成重载。
public class MethodDemo1 {
public static float fn(int a) {
//方法体
}
}
public class MethodDemo2 {
public static float fn(int a) {
//方法体
}
}
以上看似两个完全一样的方法,因为在不同的类中,所以也不构成重载。
【例4】参数顺序。
public class MethodDemo {
public static void fn(int a, double b) {
//方法体
}
public static void fn(double a, int b) {
//方法体
}
形参个数一样,方法名字一样,但是类型排列的顺序不同,这个时候也构成重载。
三、方法的使用
【练习1】数组遍历。
需求:设计一个方法用于数组遍历,要求遍历结果打印在一行。
public class Test {
public static void main(String[] args) {
//1.定义数组
int[] arr = {11, 22, 33, 44, 55};
//2.调用遍历方法
printArr(arr);
}
//定义方法用于数组的遍历
public static void printArr(int[] arr) {
System.out.print("[");
for(int i = 0; i < arr.length - 1; i++) {
System.out.print(arr[i] + ", ");
}
System.out.println(arr[arr.length - 1] + "]");
}
}
【练习2】求数组最大值。
需求:设计一个方法,求数组的最大值,并将最大值返回。
public class Test {
public static void main(String[] args) {
//1.定义数组
int[] arr = {11, 22, 33, 44, 55};
//2.调用方法求最大值
int max = getMax(arr);
//3.打印
System.out.println(max);
}
//定义方法用于数组求最大值
public static int getMax(int[] arr) {
int max = arr[0];
for(int i = 1; i < arr.length; i++) {
if(arr[i] > max) {
max = arr[i];
}
}
return max;
}
}
【练习3】定义一个方法,判断数组中的某一个数是否存在,将结果返回给调用处。
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
int[] arr = {1, 5, 8, 12, 56, 89, 34, 67};
//生成一个输入对象
Scanner sc = new Scanner(System.in);
//输入num
int num = sc.nextInt();
boolean flag = contains(arr, num);
System.out.println(result);
}
//定义一个方法,判断数组中某一个数是否存在
public static boolean contains(int[] arr, int num) {
for(int i = 0; i < arr.length; i++) {
if(arr[i] == num) {
return true;
}
}
return false; //循环完毕后仍找不到,所以返回false
}
}
【练习4】定义一个方法copyOfRange(int[] arr, int from, int to),将数组 arr 中从索引 from(包含 from)开始,到索引 to 结束(不包含 to)的元素复制到新数组中,将新数组返回。
public class Test {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int[] newArr = copyOfRange(arr);
System.out.println(newArr);
}
public static int[] copyOfRange(int[] arr, int from, int to) {
//定义新数组,不知道存几个,所以定义动态数组
int[] newArr = new int[to - from];
//用循环把数组元素挨个存储到新数组中
for(int i = from, j = 0; i < to; i++, j++) {
newArr[j] = arr[i];
}
//把新数组返回
return newArr;
}
}
四、方法的内存原理
4.1 方法调用的基本内存原理
【例1】单个方法
public class MethodDemo {
public static void main(String[] args) {
int number = 100;
sout("number的值为:" + number);
}
}
上述代码中,MethodDemo 中仅有一个 main 方法,且没用到 new 关键字,因此不涉及堆内存,仅仅使用到了栈。
在调用 main 方法时,方法会进入栈底,然后执行方法中的语句。方法中定义的变量和其值是实实在在存储于栈里的。
执行完毕后,main 方法会出栈,而里面存储的 int number 变量也会随之消失。
【例2】嵌套方法调用。
public class MethodDemo {
public static void main(String[] args) {
eat();
}
public static void eat() {
study();
System.out.println("吃饭");
sleep();
}
public static void sleep() {
System.out.println("睡觉");
}
public static void study() {
System.out.println("学习");
}
}
现在有三个方法和一个 main 方法。首先会调用 main 方法,main 方法先进栈,然后在 main 方法里调用了 eat 方法,因此 eat 方法第二个进栈;在 eat 方法中,调用了 study 方法, 因此 study 方法第三个进栈,如下:
当“学习”打印完以后,study 方法执行完毕,就会出栈:
然后打印“吃饭”,调 sleep 方法,sleep 方法也会进栈。
当“睡觉”被打印,sleep 方法也执行完毕,出栈。
此时发现,eat 方法也执行完毕,因此它也出栈。
eat 方法执行完后,main 方法也执行完毕,因此出栈,栈空。
4.2 方法传递基本数据类型的内存原理
Java 中的数据类型分为基本数据类型和引用数据类型。
基本数据类型包括:整数、浮点数、布尔、字符。除此之外的所有数据类型都是引用数据类型。它们最本质的区别是:
基本数据类型在内存中,变量存储的是真实的数据。
而引用数据类型,其存储的是一段地址值,使用了其他空间中的数据,以数组为例:
因此,在传递形参时,如果传递的是数组,它是引用类型,通过修改这个数组,可以直接影响到其指向的地址值所在的堆内存空间。