方法
比较两张图的代码,说一说感受
通过上述代码我们可以清晰的发现方法改进代码有以下几个优点:
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、方法的重载和返回值类型、访问权限修饰符无关
示例代码
1和2、3 类型不同
1和4个数不同
3和5顺序不同
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);
}
}