Java 方法详解
一、何谓方法
\quad
在前面几个章节中我们经常使用到 System.out.println()
,那么它是什么呢?println()
是一个方法;System
是系统类;out
是标准输出对象。
\quad
那么什么是方法呢?Java
方法是语句的集合,它们在一起执行一个功能。
\qquad
1. 方法是解决一类问题的步骤的有序组合。
\qquad
2. 方法包含于类或对象中。
\qquad
3. 方法在程序中被创建,在其他地方被引用。
\quad 设计方法的原则:方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成一个功能,这样有利于我们后期的扩展。
\quad
方法的优点:
\qquad
1. 使程序变得更简短而清晰。
\qquad
2. 有利于程序维护。
\qquad
3. 可以提高程序开发的效率。
\qquad
4. 提高了代码的重用性。
\quad
方法的命名规则:
\qquad
1. 方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例:addPerson
。
\qquad
2.下划线可能出现在 JUnit
测试方法名称中用以分隔名称的逻辑组件。一个典型的模式是:test<MethodUnderTest>_<state>
,例:testPop_emptyStack
。
二、方法的定义及调用
2.1 方法的定义
-
Java
的方法类似于其他语言的函数,是一段用来完成特定功能的代码片段,一般情况下,定义一个方法包含以下语法:修饰符 返回值类型 方法名(参数类型 参数名){ ... 方法体 ... return 返回值; }
-
方法包含一个方法头和一个方法体。下面是一个方法的所有部分:
- 修饰符:修饰符,这是可选的,告诉编译器如何调用该方法。定义了该方法的访问类型。
- 返回值类型:方法可能会有返回值。
returnValueType
是方法返回值的数据类型。有些方法执行所需的操作,但没有返回值。在这种情况下,returnValueType
是关键字void
。 - 方法名:是方法的实际名称。方法名和参数表共同构成方法签名。
- 参数类型:参数像是一个占位符。当方法被调用时,传递值给参数。这个值被称为实参或变量。参数列表是指方法的
参数类型
、顺序
和参数的个数
。参数是可选的,方法可以不包含任何参数。- 形式参数:在方法被调用时用于接收外界输入的数据。
- 实参:调用方法时实际传给方法的数据。
- 方法体:方法体包含具体的语句,定义该方法的功能。
-
注:在一些其它语言中方法指过程和函数。一个返回非
void
类型返回值的方法称为函数;一个返回void
类型返回值的方法叫做过程。
2.2 方法的调用
2.2.1 非静态方法
- 非静态方法就是没有
static
修饰的方法,对于非静态方法的调用,是通过对象来调用的,表现形式如下:对象名.方法(参数)
。
2.2.2 静态方法
- 静态方法就是用
static
修饰的方法,静态方法的调用是通过类名来调用的,表现形式如下:类名.方法(参数)
2.2.3 方法与方法之间的调用
1. 静态方法内部调用其他方法
- 如果在本类当中,静态方法可以直接调用其他静态方法,除了在
main
方法中,还可以在自定义的静态方法中直接调用。 - 如果在本类当中,静态方法调用非静态方法必须通过对象来调用。
- 如果不在同一个类中,静态方法调用其他类中的静态方法,必须通过
类名.静态方法()
; - 如果不在同一个类中,静态方法调用其他类的非静态方法,需要导入该类所在的包,并通过
创建对象调用
。
2. 非静态方法内部调用其他方法
- 如果在本类中,非静态方法可以
直接调用
静态方法与非静态方法。 - 在不同类中,非静态方法调用其他类的静态方法时,需要通过导入该类所在的包,并且需要通过
类名来调用
。 - 在不用类中,非静态方法调用其他类的非静态方法时,需要导入该类所在的包,还需要通过
创建对象
来调用。
3. 示例:比较两个数大小并返回大的值
import java.util.Scanner;
public class Demo01 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入第一个数:");
int num1 = scanner.nextInt();
System.out.print("请输入第二个数:");
int num2 = scanner.nextInt();
Demo01 demo01 = new Demo01();
int maxNum = demo01.max(num1,num2);
System.out.println("两个值中最大的值:"+maxNum);
}
public int max(int num1, int num2) {
System.out.printf("输入的两个值为:%d,%d\n",num1,num2);
int maxNum = num1;
if (num1 == num2) {
return maxNum;
} else if (num1 > num2) {
maxNum = num1;
} else {
maxNum = num2;
}
return maxNum;
}
}
四、方法重载
- 重载就是在一个类中,有相同的函数名称,但形参不同的函数。
- 方法的重载的规则:
- 方法名称必须相同。
- 参数列表必须不同(参数个数不同、数据类型不行、参数排列顺序不同等)。
- 方法的返回类型可以相同也可以不同。
- 仅仅返回类型不同不足以成为方法的重载。
main
方法也可以被重载。- 实现理论:方法名称相同时,编译器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
五、命令行传参
Java
程序的入口是main
方法,而main
方法可以接受一个命令行参数,它是一个String[]
数组。Java
命令行参数是一个参数,即在运行Java
程序时传递的参数。- 从控制台传递的参数可以在
Java
程序中接收,并且可以用作输入。 - 示例:我们可以利用接收到的命令行参数,根据不同的参数执行不同的代码。
上面这个程序在命令行执行,我们先编译它:public class Demo02 { public static void main(String[] args) { for (String arg:args) { if (arg.equals("version")) { System.out.println("版本:1.0"); } else if (arg.equals("author")) { System.out.println("作者:FanDong"); } else if (arg.equals("date")) { System.out.println("日期:2021.11.20"); } else { System.out.println("没有找到指令"); } } } }
javac -encoding utf-8 Demo02.java
然后,执行的时候,给它传递一个date
参数:java method.Demo02 date
六、可变参数
- 从
Java 5
开始,Java
中提供了变长参数,允许在调用方法时传入不定长度的参数。 Java
的变长参数本质上还是基于数组的实现,即void func(String... args);
等同于void func(String[] args);
。- 调用可变参数方法,可以给出零到任意多个参数,编译器会将可变参数转化为一个数组。也可以直接传递一个数组。
- 调用一个被重载的方法时,如果此调用既能够和固定参数的重载方法匹配,也能够与可变长参数的重载方法匹配,则选择固定参数的方法。
- 调用一个被重载的方法时,如果此调用能够和两个可变长参数的重载方法匹配,则编译出错。
- 在定义方法时,在最后一个形参后加上三点
...
,就表示该形参可以接受多个参数值,多个参数值被当成数组传入。上述定义有几个要点需要注意:- 可变参数只能作为函数的最后一个参数,但其前面可以有也可以没有任何其他参数。
- 由于可变参数必须是最后一个参数,所以一个函数最多只能有一个可变参数。
Java
的可变参数,会被编译器转型为一个数组。
- 示例:从
10
个范围[0, 100)
随机数中找到最大数。public class Demo03 { public static void main(String[] args) { double[] numArray = new double[10]; for (int i = 0; i < 10; i++) { numArray[i] = Math.random()*100; System.out.println(numArray[i]); } double max = maxNum(numArray); System.out.println("最大数:"+max); } public static double maxNum(double ... num) { double max = num[0]; for (double m:num) { if (m > max) { max = m; } } return max; } }
七、递归
7.1 递归的解释
- 程序直接或者间接调用自身的编程技巧叫做递归。
- 递归通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。
- 递归的能力在于用有限的语句来定义对象的无限集合。
7.2 递归的条件
- 边界条件
- 递归前进段(当边界条件不满足时,递归前进)
- 递归返回段(当边界条件满足时,递归返回)
7.3 注意事项
- 递归一定要有条件限定,保证递归可以停下来,否则会形成死循环并发生栈内存溢出(
StackOverflowError
)。 - 递归中虽然限定了停止下来的条件,但是递归次数不能太多,否则也会发生栈内存溢出
- 禁止构造方法递归。
7.4 案例
例 1
:计算阶乘
public class Demo04 {
public static void main(String[] args) {
// 10的阶乘
int result = factorial(10);
System.out.println(result);
}
// 阶乘方法
public static int factorial(int num){
if (num == 1) {
return 1;
} else {
// 使用递归思想计算阶乘
return num * factorial(num - 1);
}
}
}
例 2
:计算斐波那契数列的第 n
个数字。斐波那契数列:1,1,2,3,5,8,13,21,34,55,89,144
直到无穷大。这个数列从第 3
项开始,每一项都等于前两项之和。
public class Demo05 {
public static void main(String[] args) {
System.out.println("请输入数字:");
Scanner scanner = new Scanner(System.in);
int i = scanner.nextInt();
System.out.println("第"+i+"个数字为"+add(i));
}
// 前两项之和
public static int add (int num) {
if (num == 1 || num == 2) {
return 1;
}
return add(num - 1) + add(num - 2);
}
}