Day07-方法
学习目标
- 方法的概念
- 方法的格式
- 方法的调用
- 方法调用的内存结构
- 方法的重载
- 可变参数
- 递归
1. 方法
1.1 什么是方法
方法也叫函数,是一组代码语句的封装,从而实现代码重用,从而减少冗余代码,通常它是一个独立功能的定义,方法是一个类中最基本的功能单元。
1.2 声明方法
- 声明方法的位置
方法必须声明在类中 且不能嵌套使用
类{
方法1(){
}
方法2(){
}
}
-
声明方法的语法格式
public static 返回值类型 方法名([形参列表]){ 方法体的功能代码 } public static void showMessage(){ System.out.println("HelloWorld"); } []:包裹内容可有可无
- public static 是方法的修饰符 公共的 静态的
- 返回值类型:表示方法运行的结果的数据类型,方法执行后将结果返回到调用者
- 方法名:给方法起一个名字,见名知意,能准确代表该方法功能的名字
- 形参列表:表示完成方法体功能时需要外部提供的数据列表
- 方法体:方法体必须有{}括起来,在{}中编写完成方法功能的代码
1.3 方法的调用
使用方法名调用:方法的执行顺序只和调用有关和声明无关
public class MethodTest {
public static void main(String[] args) {
showHello();
}
public static void showHello() {
System.out.println("HelloWorld");
}
}
1.4 方法的形参
方法的形参:
1.方法的声明处
2.规定方法实参的数量和类型
方法的实参:
方法调用者传递的实际的值
public class MethodTest3 {
//方法的声明
public static void sum(int a,int b){//形参
System.out.println(a+b);
}
public static void main(String[] args) {
sum(10,30);//实参
}
}
1.5 方法的返回值
有的时候需要方法执行的结果作为下次执行的条件就需要带返回值的方法
public static 返回值类型 方法名([形参列表]){
方法体的功能代码
}
返回值类型:
void:没有返回值
数据类型:必须通过 return 关键字 返回一个该类型匹配的值
- return语句的作用是结束方法的执行,并将方法的结果返回去
- 如果返回值类型不是void,方法体中必须保证一定有 return 返回值; 语句,并且要求该返回值结果的类型与声明的返回值类型一致或兼容。
- 如果返回值类型为void时,方法体中可以没有return语句,如果要用return语句提前结束方法的执行,那么return后面不能跟返回值,直接写return ; 就可以。
- return语句后面就不能再写其他代码了,否则会报错:Unreachable code
public class MethodTest4 {
//方法的声明
public static int sum(int a,int b){//形参
return a+b;
}
public static void main(String[] args) {
int result = sum(10,30);//实参
System.out.println("result = "+ result);
}
}
1.6 方法的内存调用
方法不调用不执行,调用一次执行一次,每次调用会在栈中有一个入栈动作,即给当前方法开辟一块独立的内存区域,用于存储当前方法的局部变量的值,当方法执行结束后,会释放该内存,称为出栈,如果方法有返回值,就会把结果返回调用处,如果没有返回值,就直接结束,回到调用处继续执行下一条指令。
栈结构:先进后出,后进先出。
public class MethodTest3 {
public static void main(String[] args) {
showHello();
}
public static void showHello() {
System.out.println("HelloWorld");
int result = sum(10, 20);
System.out.println("result = " + result);
}
public static int sum(int m, int n) {
return m + n;
}
}
2 方法的重载
-
方法重载:在同一类中使用相同的方法名表示不同细节实现的方法
-
方法重载的注意:
- 同一类中同一方法名不同的形参列表
不同的形参列表:类型 顺序 个数 - 与返回值类型和修饰符无关
- 同一类中同一方法名不同的形参列表
-
重载方法调用:JVM通过方法的参数列表,调用匹配的方法。
- 先找个数、类型最匹配的
- 再找个数和类型可以兼容的,如果同时多个方法可以兼容将会报错
案例,用重载实现:
(1)定义方法求两个整数的最大值
(2)定义方法求三个整数的最大值
(3)定义方法求两个小数的最大值
(4)定义方法求n个整数最大值
package com.atguigu.test06.overload;
public class MathTools {
//求两个整数的最大值
public static int max(int a,int b){
return a>b?a:b;
}
//求两个小数的最大值
public static double max(double a, double b){
return a>b?a:b;
}
//求三个整数的最大值
public static int max(int a, int b, int c){
return max(max(a,b),c);
}
//求n整数的最大值
public static int max(int... nums){
int max = nums[0];//如果没有传入整数,或者传入null,这句代码会报异常
for (int i = 1; i < nums.length; i++) {
if(nums[i] > max){
max = nums[i];
}
}
return max;
}
}
3 可变参数
当定义一个方法时,形参的类型可以确定,但是形参的个数不确定,那么可以考虑使用可变参数。可变参数的格式;
public 返回值类型 方法名(【非可变参数部分的形参列表,】参数类型... 形参名){
}
特点:
(1)一个方法最多只能有一个可变参数(语法规定)
(2)如果一个方法包含可变参数,那么可变参数必须是形参列表的最后一个
(3)在声明它的方法中,可变参数当成数组使用
(4)可变参数中实参的数量[0,n]
package com.atguigu.test05.param;
public class NumberTools {
public static int total(int[] nums){
int he = 0;
for (int i = 0; i < nums.length; i++) {
he += nums[i];
}
return he;
}
public static int sum(int... nums){
int he = 0;
for (int i = 0; i < nums.length; i++) {
he += nums[i];
}
return he;
}
public static void main(String[] args) {
System.out.println(NumberTools.sum());//0个实参
System.out.println(NumberTools.sum(5));//1个实参
System.out.println(NumberTools.sum(5,6,2,4));//4个实参
System.out.println(NumberTools.sum(new int[]{5,6,2,4}));//传入数组实参
System.out.println("------------------------------------");
System.out.println(NumberTools.total(new int[]{}));//0个元素的数组
System.out.println(NumberTools.total(new int[]{5}));//1个元素的数组
System.out.println(NumberTools.total(new int[]{5,6,2,4}));//传入数组实参
}
}
4 方法的值传递
4.1 基本类型数据的值:传递的是值的副本
public class ChangeValue1 {
public static void main(String[] args) {
int m = 10;
int n = 20;
System.out.println("方法调用前 m = " + m+", n = "+ n);
swap(m,n);
System.out.println("方法调用后 m = " + m+", n = "+ n);
}
public static void swap(int m, int n) {
int temp =m;
m = n;
n =temp;
System.out.println("方法调用中 m = " + m+", n = "+ n);
}
}
4.2 数组作为参数:传递的是地址值
public class ChangeValue2 {
public static void main(String[] args) {
String[] arr = {"安琪拉","米莱迪","妲己"};
System.out.println("交换前:"+ arr[0]);//安琪拉
swap(arr);
System.out.println("交换后:"+ arr[0]);// 安琪拉 林志玲
}
public static void swap(String[] arr) {
arr[0]="林志玲";
System.out.println("交换中:"+ arr[0]);//林志玲
}
}
5 递归
5.1 递归的应用
递归:方法自己调用自己的现象就称为递归。
递归的分类:
- 递归分为两种,直接递归和间接递归。
- 直接递归称为方法自身调用自己。
- 间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。
注意事项:
-
递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
-
在递归中虽然有限定条件,但是递归深度不能太深,否则效率低下,或者也会发生栈内存溢出。
- 能够使用循环代替的,尽量使用循环代替递归
递归调用的内存图
求100到1的和
public class Test {
public static void main(String[] args) {
int sum = sum(5);
System.out.println("sum = " + sum);
}
// 100+99 +98 +97 ....+1
public static int sum(int num){
if(num==1){
return 1;
}
return num+sum(num-1);
}
}
5.2 菲波那切数列
计算斐波那契数列(Fibonacci)的第n个值,斐波那契数列满足如下规律,
1,1,2,3,5,8,13,21,....
即从第三个数开始,一个数等于前两个数之和。假设f(n)代表斐波那契数列的第n个值,那么f(n)满足:
f(n) = f(n-2) + f(n-1);
package com.atguigu.test07.recursion;
public class FibonacciTest {
public static void main(String[] args) {
int result = feibo(4);
System.out.println("result = " + result);
}
//使用递归的写法
int feibo(int n){//计算斐波那契数列第n个值是多少
if(n<1){//负数是返回特殊值1,表示不计算负数情况
return 1;
}
if(n==1 || n==2){
return 1;
}
return feibo(n-2) + feibo(n-1);
}
//不用递归
int fValue(int n){//计算斐波那契数列第n个值是多少
if(n<1){//负数是返回特殊值1,表示不计算负数情况
return 1;
}
if(n==1 || n==2){
return 1;
}
//从第三个数开始, 等于 前两个整数相加
int beforeBefore = 1; //相当于n=1时的值
int before = 1;//相当于n=2时的值
int current = beforeBefore + before; //相当于n=3的值
//再完后
for(int i=4; i<=n; i++){
beforeBefore = before;
before = current;
current = beforeBefore + before;
/*
假设i=4
beforeBefore = before; //相当于n=2时的值
before = current; //相当于n=3的值
current = beforeBefore + before; //相当于n = 4的值
假设i=5
beforeBefore = before; //相当于n=3的值
before = current; //相当于n = 4的值
current = beforeBefore + before; //相当于n = 5的值
....
*/
}
return current;
}
}