05.JAVASE 方法 & 在内存的执行原理
方法的引入:简化了代码;提高了可读性;提高了扩展性;提高了维护性
概述:完成特定的代码片段,通过类似于y = f(x ,y )的形式调用
文章目录
1.方法的格式和定义
1.1方法格式
[访问权限修饰符] 返回值类型[输出的类型] 方法名(参数类型 变量1 ,参数类型 变量2 … ) [throw 异常类名] {
方法体;
return 返回值;
}
1.2方法的定义
-
访问权限修饰符:暂时使用 public static
-
返回值类型:八大基本数据类型和引用数据类型,选用类型要是和返回值类型符合类型转换也可以
类型转换:
1. 9种基本数据类型转换 2. 引用类型转换 [ 向上转型 和 向下转型 ]
-
方法名:符合命名规范,见名知意,开头动词
-
return
- 单独使用就直接退出当前所在的方法
- return 返回值:中的返回值类型要和方法定义的返回值类型保持一致,后符合类型转换
- 方法没有返回值则在定义方法时,返回值类型为: void
- 只要声明了返回值类型(非void),就必须返回 [ return 返回值 ] 给调用者
方法定义的位置:类体内,方法体外
1.21定义的三要素
- 参数列表(输入)
- 返回值类型(输出)
- 方法名(调用)
2.方法的调用
2.1方法调用的三要素
- 需要什么参数类型就设置什么参数类型
- 返回什么类型的返回值就用什么类型接收
- 方法参数的 个数 类型 顺序 必须保持一致
2.2方法的调用方式
- 直接调用 [ 适用于方法的返回值类型为:void 的情况]
- 输出调用 [ 适用于方法的返回值后续不需要使用,直接打印输出的情况 eg:syso ]
- 赋值调用 [ 适用于方法的返回值不是直接输出的,需要参与后续代码的执行]
3.方法的重载(Overload)
解决了多个方法参数不同,但功能相同的重名问题
简化了代码,提高了扩展性和维护性
概述:在同一个类中,方法名字相同,参数列表不同则构成重载
3.1方法重载的特点
- 在同一个类中
- 方法名称相同
- 方法的参数 个数 数据类型 顺序 都可构成重载
- 方法重载与访问权修饰符 返回值类型 没有关系(但与重写有关系)
- 方法重载是多态的一种表现
- 方法调用时,满足精确性原则和准确性原则
//准确性原则
add(10,2.5)
//方法一
public static double add(int a, double b) {
System.out.println("x");
return a + b;
}
//方法二
public static double add(int a, int b) {
System.out.println("y");
return a + b;
//会使用方法二
//精确性原则
add(10,20)
public static double add(int a, double b) {
System.out.println("x");
return a + b;
}
public static double add(int a, byte b) {
System.out.println("y");
return a + b;
}
//两个方法都适用时,系统会报错
//The method add(int, double) is ambiguous for the type MethodDemo03
//因为没有方法符合准确性原则,但两个方法都能执行
4.方法递归
递归是对自身回路的重复
递归通过方法实现,即方法对自身的调用
特点:
- 递归必须有出口,否者会出现死递归
- 递归次数太多,建立的栈帧过多,会出现内存溢出
- 构造方法不能递归
4.1递归问题
-
//为什么是i--会报错内存溢出呢, //而--i则不会 public class MethodDemo04 { public static void main(String[] args) { diGuiTellStory(10); } // 递归讲故事 老和尚和小和尚的故事 public static void diGuiTellStory(int i) { if (i == 0) { return; } System.out.println("从前有座山,山里有座庙,庙里有个老和尚和小和尚," + "老和尚对小和尚说: 故事是: " + i); diGuiTellStory(--i); //diGuiTellStory(i--); } } //因为代码中的i = 10把值赋给了新的diGuiTellStory(int i)方法, //在内存中是以新的栈帧存储的,旧的方法内i确实把i赋值后--了,i = 9; //但新的栈帧内的方法依据是i = 10; //所以就会出现死递归,建立过多的栈帧导致内存溢出,报错
-
/* * 递归求5的阶乘以及斐波那契数列 * 5 * 4 * 3 * 2 * 1 * * 120 * return 5 * 24 * return 4 * 6 * return 3 * 2 * return 2 * 1 * return 1 */ public class MethodDemo05 { public static void main(String[] args) { System.out.println(getJieChengByLoop(5)); System.out.println(getJieChengByDiGui(5)); System.out.println(fiboonaqi(4)); } public static long getJieChengByLoop(int num) { long jc = 1; for (int i = 1; i <= num; i++) { jc *= i; } return jc; } //递归的条件有一条就是必须要有return,防止死循环 //所以满足所设置出口的条件后就会执行return //这里就会有一个概念的问题,return的作用是退出方法,返回调用者 //即返回的是上一个递归方法,而不是直接返回到main的主方法,是逐层返回的
4.2死递归和死循环的区别
死循环是可以得 (eg:飞行的小鸟就是通过不同的图片不断循环形成的飞行动作
死递归会报错,内存溢出
5.方法在内存中的执行原理
内存(RAM):运行时的存储
特点:在程序运行时,开辟空间,在程序执行结束后关闭空间,所有数据都会清除
5.1JVM的组成 & 内存分配
- 类加载器:
- 运行时数据区
- 栈区:存放局部变量(方法体内定义的变量 & 方法定义时声明的变量 [ 形参 ])
- 堆区:存放new出来的东西 ( eg:int[ ] arr = new int[3]; Scanner input = new Scanner(System.in);)
- 方法区(代码区 永久区)[ 内存中的数据库 ]:存放代码,静态的东西,常量池
- 本地方法区:和系统相关
- 寄存器:和CPU计算相关,主要给CPU使用
- 执行引擎
- 本地接口
5.1.1栈区的特点
- 先进后出(子弹夹)
- 栈内存的数据只对相对应的作用域有效,且只用完后就会立即释放
( eg:在方法体内定义的变量只能在该方法内使用,在别的栈帧是不能使用的) - 栈区的变量是没有默认值得,所以需要赋值才能使用,要不然会报错