3、方法
重点:
1、方法的定义与调用
2、方法的参数
3、方法的返回值
4、方法的重载
难点:
1、方法的参数
2、方法的返回值
3.1、方法的简介
方法,是对一段代码段的封装。可以把一段具有执行功能的代码段封装起来,做成一个方法。这样做的话,可以做到重复使用。一次包装,多次使用。
循环:要求重复执行的代码段之间,重复是有一定的规律的。
在Java中,方法和函数其实是概念模糊的。方法近似可以认为是函数,函数近似可以认为是方法。
3.2、方法的定义
基本语法
[访问权限修饰符] [其他修饰符] 返回值类型 方法名([参数列表]) {
// 方法体
}
访问权限修饰符:决定了这个方法可以在哪些地方使用。在后面继承部分讲。
其他修饰符:修饰了这个方法的一些其他的特性。在后续课程中不断完善。
返回值类型:当还没有讲到返回值的时候,先写void。
方法名:是一个标识符,遵循小驼峰命名法。
参数列表:由所有的参数组成的一个列表。
[]:中括号部分代表可有可无。
注意事项:
在Java中,方法定义在类中,方法与方法是平级的,不允许出现方法嵌套方法。
void nineTables() {
for (int line = 1; line <= 9; line++) {
for (int colum = 1; colum <= line; colum++) {
System.out.print(colum + " x " + line + " = " + colum * line + "\t");
}
System.out.println();
}
}
3.3、方法的调用
一个方法定义完成后,里面的代码段是不会自动执行的(main方法除外)。如果要执行一个方法中的逻辑,需要将这个方法进行调用。
静态的方法,只能直接调用当前类中的静态方法。不能直接调用非静态的方法。
PS:使用关键字static修饰的方法,就是静态方法。
1、如何调用一个方法:
方法是条狗,哪里需要哪里吼。当我们需要调用一个方法的时候,可以直接通过这个方法的名字来调用。要注意:在调用方法的时候,方法名后面是需要加小括号的。
public static void main(String[] args) {
// 调用一个方法,执行这个方法中的逻辑
nineTables();
}
3.4、方法的内存分析
在JVM虚拟机内存中,将内存分为几个区:栈。
栈和队列:
如果将栈和队列放到一起,此时的栈,代表是一种数据结构。栈结构的存储特点:先进后出,后进先出。
先向栈中添加的元素,会在栈底存储。后向栈中添加的元素,会在栈顶存储。
从栈中向外取数据的时候,先去出来,一定是后添加的。
队列,也是一种数据结构。队列的存储特点:先进先出,后进后出。
栈和堆:
如果将栈和堆放到一起,其实栈,代表的是内存中的一块空间。栈空间。
方法定义完成后,会在方法区中存储。在调用方法的时候,会将方法从方法区中取出,压到栈空间中执行。
多个方法相互调用的时候,这些方法执行的先后顺序
public static void main(String[] args) {
System.out.println("0");
test1();
System.out.println("5");
// 最后的输出结果:0,1,3,2,5
}
static void test1() {
System.out.println("1");
test2();
}
static void test2() {
test3();
System.out.println("2");
}
static void test3() {
System.out.println("3");
}
3.5、方法的参数
局部变量:
指的是定义在某一个代码段中,而不是在类中定义的变脸。
变量的作用域:
每一个局部变量,都有自己可以生效的范围。这个范围,称为一个局部变量的作用域。
两个局部变量的作用域是不能重叠的。因为一旦发生了重叠,则在重叠部分,将无法对这两个变量进行区分。
如何确定一个变量的作用域:
从声明变量开始,到声明变量所在的代码段结束。
3.5.1、参数的定义
参数,其实就是一个变量。只不过,这个变量是定义在参数列表的小括号中的。
和普通的变量有区别的:
1、定义位置不同,参数需要定义在参数列表的小括号中。
2、参数定义在参数列表中,不允许有初始的值。
3、即使是需要定义多个相同类型的参数,那么每一个参数的类型也必须要明确写出。
static void calculate(int a, int b) {}
3.5.2、调用有参的方法
注意事项:
在调用有参方法的时候,需要给每一个参数进行赋值。要保证参数列表中的参数数量和类型是一致的。
public static void main(String[] args) {
calculate(10, 20);
}
static void calculate(int a, int b) {
System.out.println(a);
System.out.println(b);
}
三个概念:
1、定义在方法的参数列表中的参数,在方法中,只有一个形式作用。也就是说,在方法内部,其实是不知道这两个参数的值。这样的参数,叫做形式参数。简称 形参。
2、在调用方法的时候,小括号中的参数,起到了实际的作用。是将这个参数给形参去赋值的。因此,这样的参数,叫做实际参数。简称 实参。
3、在调用方法的时候,用实参给形参赋值。这个过程,叫做 传参。
3.5.3、参数的实际使用场景
参数,有一个最重要的作用:就是让某一个值在两个方法中进行传递。
可以通过参数,将一个方法中的值,传递到另外一个方法中。
public static void main(String[] args) {
for (int n = 2; n <= 100; n++) {
test(n);
}
}
// 判断一个数字是不是质数,如果是,输出
static void test(int n) {
boolean flag = true;
for (int i = 2; i <= n / 2; i++) {
if (n % i == 0) {
flag = false;
break;
}
}
if (flag) {
System.out.println(n);
}
}
3.5.4、参数的传递问题
public class Program {
public static void main(String[] args) {
int a = 10, b = 20;
swap(a, b);
System.out.println("a = " + a + ", b = " + b);
}
/**
* 交换两个参数的值
* @param x
* @param y
*/
public static void swap(int x, int y) {
x = x ^ y;
y = x ^ y;
x = x ^ y;
}
}
在上述代码中,main函数中调用swap方法,这个过程中,a和x赋值、b给y赋值。
然后在swap方法中,对x和y的值进行了交换。
但是,x值的改变,不会影响到a,因为他们不是同一个变量;同理,y的改变也不会影响到b。
因此,最后的结果是 a = 10, b = 20
3.6、方法的返回值
3.6.1、返回值的定义
1、什么是返回值?
返回值,其实就是一个方法执行的结果。在一个方法中,可能封装了若干代码段,执行了某种功能。最终这些代码段执行的结果是什么。
2、如何定义返回值?
方法的语法部分,有一段就是返回值类型,写在方法名的前面。
void:只能用在方法的返回值部分,代表无返回值。
3、定义返回值注意事项
如果一个方法的返回值类型声明不是void,那么在这个方法执行结束之前,必须要有一个确定的值返回。并且,这个返回值的类型,一定要和方法声明的时候声明的类型匹配。
注意:
如果在方法中出现了分支,必须要保证所有情况下,都有结果返回。
// 错误案例:
// 机器不是智能的,它不会去处理这种逻辑分支。
// 机器只认识,这里有一个if,但是没有else。
// 所以,这一段代码会出错。
static int abs(int a, int b) {
if (a > b) {
return a - b;
}
else if (a < b) {
return b - a;
}
else if (a == b) {
return 0;
}
}
4、return关键字
- 写在方法中,表示这个方法的执行结果是什么。return后面跟的值,作为这个方法的返回值。
- return表示结束方法,return后面的语句,都不执行。
Q:在一个无返回值的方法中(方法的返回值类型是void),能不能使用return?
A:可以!此时return后面什么都不要写,直接写分号结束。此时的return仅表示结束方法。
3.6.2、使用返回值实现不同方法之间的数据传递
public static void main(String[] args) {
for (int i = 100; i <= 999; i++) {
if (check(i)) {
System.out.println(i);
}
}
}
/**
* 传入一个数字,判断这个数字是不是水仙花数
*
* @param number
* 需要判断的数字
* @return 判断的结果
*/
static boolean check(int number) {
// 1、位数判断
if (number < 100 || number > 999) {
return false;
}
// 2、取出每一位
int b = number / 100;
int s = number / 10 % 10;
int g = number % 10;
// 3、进行水仙花数的判断
boolean result = g * g * g + s * s * s + b * b * b == number;
// 4、将判断结果返回
return result;
}
3.7、方法的重载
3.7.1、什么是重载
如果在一个类中的方法,满足如下要求:
- 方法名相同。
- 参数不同。(体现在:数量不同,类型不同)
这些方法,彼此之间的关系,叫做重载(Overload)。
3.7.2、如何区分调用重载的方法
在调用方法的时候,使用方法名来调用。但是,重载的方法,方法名是相同的。因此,对于重载的方法,无法通过方法名来区分。在调用的时候,需要找到这些方法之间的不同点。
在区分调用重载方法的时候,通过参数来区分。
public static void main(String[] args) {
show(); // 无参的show方法
show(1); // show(int)
show(1, 3.2f); // show(int, float)
}
static void show() {
System.out.println("无参的show方法");
}
static void show(int a) {
System.out.println("show(int)");
}
static void show(int a, float b) {
System.out.println("show(int, float)");
}
3.7.3、重载方法的使用场景
重载,其实并不能够节省代码量。可以让我们对若干具有相似功能的方法,在调用的时候,不必刻意区分。
例如:System.out.println();
这个方法,参数可以是任意类型。因此,当我们需要将数据输出到控制台的时候,直接使用这个方法即可。而不用纠结输出哪一种数据,需要调用哪一个方法。
3.8、方法的递归
3.8.1、方法递归的简介
递归,其实就是方法之间的循环调用。例如方法调用自己。
3.8.2、使用递归方法的时候注意事项
递归在使用的时候,如果找不到方法执行结束的契机,会无限制的向栈中压方法。最终,会出现StackOverflowError的错误。
/**
* 计算第index位的斐波那契数列中的数字
*
* @param index
* @return
*/
public static int getNumber(int index) {
if (index == 1 || index == 2) {
return 1;
}
return getNumber(index - 2) + getNumber(index - 1);
}
/**
* 计算 1 + 2 + 3 +... + n的和
* @param n
* @return
*/
public static int getSum(int n) {
if (n == 1) {
return 1;
}
return getSum(n - 1) + n;
}