Java-----方法的引入方法的定义、调用、内存原理及重载和递归的详细解析

方法

比较两张图的代码,说一说感受
在这里插入图片描述
在这里插入图片描述

通过上述代码我们可以清晰的发现方法改进代码有以下几个优点:
  1.简化了代码
  2.由于第一张图主方法中只需要调用printEven方法不需要关心具体的实现细节,从而提高了代码的可读性。
  3.如果需要修改或者添加功能只需要在printEven方法中修改,不需要所有地方一起修改,提高了代码的可维护性
  4.如果需要输出300~600的偶数,不需要再去写多余的代码,只需要通过参数传入即可,提高了代码的可维护性
  5.同时方法也是面向对象编程的核心基础。

方法的概述

一段用来完成特定功能的代码片段,在其他语言中又称为函数,其实本质就是对代码的抽取。

方法的定义

格式:
[访问权限修饰符] 返回值类型 方法名(参数类型 参数名1, 参数类型 参数名2, 参数类型 参数名3, … 参数类型 参数名n) {
   方法体;
   [return [返回值];]
}

说明:
   一、访问权限修饰符: 这里暂时使用 public static。
   二、返回值类型:
      1、这里的类型可以是八大基本数据类型也可以是引用数据类型
      2、这个类型需要和return关键字返回的类型一致,或者比返回值的类型范围更大
      3、如果一个方法的没有返回值,那么这里书写 void
   三、方法名: 满足方法名的命名规范,第一个单词首字母小写,其他单词首字母大写,满足见名知意,一般是动词
   四、参数类型: 这里的类型可以八大基本数据类型也可以是引用数据类型
   五、参数名: 这里的参数名本质就是一个变量,满足变量的命名规范,这里参数称为形式参数
   六、方法体: 功能实现的具体代码
   七、return关键字
      1、 单独使用: 【return;】 表示直接退出当前所在的方法
      2、 结合返回值使用: 【return 返回值;】这里表示先将结果返回给调用者,然后再退出当前所在的方法

方法定义的位置

  类体以内,方法体以外 【成员位置、全局位置】

方法的定义的三要素

定义一个方法首先必须要先明确一下三个要素
  1、参数列表: 完成这个功能需要用到哪些参数
  2、返回类型: 这个方法的结果类型
  3、方法名: 见名知意

方法调用的三要素

  1、方法需要什么类型的参数就给什么类型,这里的参数传递一样满足类型转换
  2、方法返回什么类型的结果就必须使用什么类型接收,这里结果的返回一样满足类型转换
  3、方法调用的参数列表必须和定义的参数列表保持一致 【顺序 类型 个数】

形式参数和实际参数【形参、实参】

  形参: 方法定义的时候的参数
  实参: 方法调用的时候的参数
  参数传递: 实参 赋值给 形参

方法调用的三种情况

  1、直接调用: 针对某个方法没有返回结果的时候使用
  2、输出调用: 针对某个方法的结果只需要直接输出,不需要后续使用的情况
  3、赋值调用: 针对某个方法的结果还需要后续使用的情况

注意事项

  1、方法不能够嵌套定义
  2、如果一个方法一旦声明了返回值类型,那么方法体内必须显示返回结果,否则会编译报错
  3、方法不调用不执行
  4、方法的书写记住不要脱离方法的功能的本质,方法功能尽量独立
  5、方法中可以再调用其他方法,方法不能够嵌套定义但是可以嵌套调用

存储方式

内存: 运行时存储
特点: 在程序运行的是开辟空间,程序执行结束,内存中数据就消失了
持久化存储: 文件 U盘 数据库等等
特点: 可以将数据永久保存。

JVM内存结构分区在这里插入图片描述

内存的分配

    栈区: 存放局部变量 ( 方法体内定义的变量 或者 方法定义的时候声明的变量【形参】)
    堆区: 存放通过new出来创建的对象
    方法区(代码区/永久区): 存放代码、方法、静态的、常量池等等
    本地方法区: 和系统相关,我们不需要了解
    寄存器: 和CPU计算相关,主要给CPU使用,我们也不需要了解

栈区的特点

    1.先进后出,类似于子弹夹
    2.栈内存中的数据仅在所对应的作用域内有效,使用完毕之后立马自动释放
    3.栈区中的变量没有默认值,如果没有给出默认值就直接使用会报错\

局部变量: 方法体内定义的变量 或者 方法定义的时候声明的变量【形参】
    public static int add(int a, int b){
        int sum = 0;
        sum = a + b;
        return sum;
    }
    其中 a, b , sum都被称作为局部变量。

方法的调用内存原理

1、方法调用会在栈区开辟空间,方法return或者执行结束会释放栈区空间
2、在每一个方法【栈帧】中的变量称为局部变量,仅在当前方法可见
3、不同的方法中可以定义相同名称的变量,互不影响,但是同一个方法中变量名必须唯一
4、如果一个采用了递归调用,但是没有显示return返回,可能会出现死递归,死递归会导致栈内存溢出。

在这里插入图片描述

示例代码
/*
	 * 功能: 计算m,n的和
	 * 返回值类型: int
	 * 参数列表: int m, int n;
	 * 方法名: getSum
	 */
	public static int getSum(int m, int n) {
		int sum = 0;
		for (int i = m; i <= n; i++) {
			sum += i;
		}
		return sum;
	}
/**
	 * 功能: 求两个数之和 add
	 * @param int m
	 * 			求两个数的和的第一个数
	 * @param int n
	 * 			求两个数的和的第二个数
	 * @return int
	 * 			返回两个数的和
	 */
	public static int add(int m, int n) {
		return m + n;
	}

方法重载

引入

解决多个方法参数列表不一样但是方法名重名的问题

概念

    方法名称相同,参数列表不同构成重载

特点

    1、发生在同一个类中
    2、法名称相同
    3、参数列表不同 【参数的顺序 类型 个数不同】
    4、重载和形参的参数名称无关
    5、重载的方法系统会根据参数的个数,顺序,类型找到对应的方法执行
    6、方法重载的准确性原则和 精确性原则
    系统如果找到同时有两个方法都满足重载的条件,会按照这两个原则来匹配
    7、方法的重载和返回值类型、访问权限修饰符无关

示例代码
123 类型不同
14个数不同
35顺序不同
public class MethodDemo01 {
	public static void main(String[] args) {
		System.out.println(add(10, 20));
		System.out.println(add(10, 40));
		// System.out.println(add(20.0, 30.0));
		System.out.println(add(10, 20, 30));
	}
	
	// 1
	/*public static double add(double a, double b) {
		return a + b;
	}*/
	// 6
	/*public static double add(double c, double d) {
		return c + d;
	}*/
	// 2
	public static double add(int a, int b) {
		return a + b;
	}
	// 3
	public static double add(int a, double b) {
		return a + b;
	}
	
	// 4
	public static double add(double a, double b, double c) {
		return a + b + c;
	}
	
	// 7
	public static double add(float a, float b, float c) {
		return a + b + c;
	}
	
	// 5
	public static double add(double a, int b) {
		return a + b;
	}
}

class A {
	public static double add(double a, double b, double c) {
		return a + b + c;
	}
}

方法递归

概述

    递归是一种算法,表示对自身回路的访问,递归在Java中的实现就是必须使用方法

递归的特点

    1、必须存在方法,方法中自己调自己
    2、 递归如果没有出口,会出现死递归
    3、 死递归和死循环的区别?
        死循环不会程序奔溃
        死递归会栈内存溢出
    4、递归要慎用,但是用得好代码很简洁

示例代码

public class MethodDemo01 {
	public static void main(String[] args) {
		diGuiTellStory(10);
	}
	
	public static void diGuiTellStory(int i) {
		/*if (i == 0) {
			System.out.println("别讲了!!!!");
			return;
		}*/
		
		System.out.println("从前有座山,山里有座庙,庙里有个老男人和小男人讲故事:那么故事是: " + i);
		diGuiTellStory(--i);
	}
}

递归经典习题

使用递归和循环分别实现 求n的阶乘`

public class MethodDemo02 {
	public static void main(String[] args) {
		System.out.println(getFactorialByLoop(5));
		System.out.println(getFactorialByRecursion(5));
	}
	
	/**
	 * 功能: 求一个数的阶乘 例如: 5! 5*4*3*2*1 getFactorial
	 * @param int num
	 * @return long
	 */
	public static long getFactorialByLoop(int num) {
		long factorial = 1;
		for (int i = 1; i <= num; i++) {
			factorial *= i;
		}
		return factorial;
	}
	
	/**
	 * 功能: 求一个数的阶乘 例如: 5! 5*4*3*2*1 getFactorial
	 * @param int num
	 * @return long
	 * 递归: 就是对自身回路的循环
	 */
	public static long getFactorialByRecursion(int num) {
		
		if (num < 1) {
			return 0;
		}
		
		// 先确定出口
		if (num == 1) {
			return 1;
		}

		return num * getFactorialByRecursion(num - 1);
	}
	

分别使用和循环求斐波那契数列的第n项的值

public class MethodDemo02 {
	public static void main(String[] args) {
		System.out.println(getFibonacciByLoop(5));
		System.out.println(getFibonacciByRecursion(5));
	}
	/**
	 * 功能: 求斐波那契数列对应的值
	 * @param count 第几项
	 * @return 第几项对应的值
	 */
	public static int getFibonacciByLoop(int n) {
		int pre2 = 1;
		int pre1 = 1;
		int current = 0;
		for (int i = 1; i <= n; i++) {
			if (i == 1 || i == 2) {
				current = 1;
			} else {
				pre2 = pre1;
				pre1 = current;
				current = pre1 + pre2;
			}
		}
		return current;
	}
	
	// 1 1 2 3 5 8 13
	public static int getFibonacciByRecursion(int n) {
		// 先确定出口
		if (n < 1) {
			return 0;
		}
		
		if (n == 1 || n == 2) {
			return 1;
		}
		/*
		 * 3 f(1) + f(2) = 1 + 1 = 2
		 * 4 f(2) + f(3) = 1 + 2 = 3
		 * 5 f(3) + f(4) = 2 + 3 = 5
		 * i f(n - 2) + f(n - 1)
		 */
		return getFibonacciByRecursion(n - 2) + getFibonacciByRecursion(n - 1);
	}
}
已标记关键词 清除标记
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页