函数复习
1,函数的位置:定义在类以内,其他函数以外
2,函数的定义:函数声明和函数的实现
public static 返回值类型 函数名(形参列表){
//函数体(函数实现部分)
}
函数三要素:函数名、形参列表、返回值类型
函数的声明:public static 返回值类型 函数名(形参列表)
3,函数的调用:
函数名(实参列表); ---> 实参和形参一致。(个数、顺序、数据类型)
函数的嵌套
- 被调函数内部调用其他函数
- 原理:执行函数遇到被调函数,则先执行被调函数内部的代码,被调用的代码执行完毕之后,如果有返回值需要带着返回值返回调用它的位置;当前函数继续执行后续代码。
函数的内存机制
-
栈(stack)空间:描述函数(方法)调用的过程而产生的一个空间分配。而且每调用一个函数(主函数一样)在栈空间产生一个栈帧空间(stack frame)
-
栈帧(stack frame):
- 记录当前函数的局部变量表、操作数、函数调用信息等
- 栈帧随着函数的调用而产生的,函数一旦调用结束,此函数的栈帧空间也被回收
-
main()函数栈帧: ---->执行完出口,即执行完跳到虚拟机处。
- 局部变量表
- 操作数
- 函数调用信息
- 函数的出口等信息
-
main()函数调用其余函数时会分配新的栈帧,新的栈帧空间执行完后出口---->执行完跳到main()处。且执行完时栈帧空间释放回收。
-
栈空间从下往上放置,然后再从上往下依次运行。不调用不分配栈帧。
函数的递归
-
一个函数中自己调用自身函数。
-
通常要为递归设置一个合适的出口,否则出现无穷递归,导致运行时报错
—>java.lang.StackOverflowError(栈溢出)
-
-
思想:
- 递进:每次的推进都比上次的计算简单,直到达到出口
- 回归:基于出口逐层往回返,直到最终调用者
-
将复杂的问题拆分成若干个小问题时,遵循的规律相同,此时可以使用递归
-
String类型便于校验,所以通常电话、地址等都用String
六、数组
-
概念
- 一次性定义多个相同类型的变量,并且可以进行统一的操作。
-
特点:
- 相同类型:数据类型
- 多个:取决于长度
-
定义:
- 声明:数据类型[] 变量名;
- 分配空间:数组名 = new 数据类型[长度];
-
下标:为了方便操作数组中的每个空间,为每个空间进行编号。范围为0~数组长度 -1
- 下标越界错误提示:java.lang.ArrayIndexOutOfBoundsException(包括上越界和下越界)
-
遍历:将数组中的元素进行一一访问
-
数组具有默认值,对应的数据类型默认值:
- 整数(byte、short、int、long) ----> 0
- 小数(float、double) ----> 0.0
- 字符(char) ----> 空字符(’\u0000’)
- 布尔(boolean) ----> false
- 引用 ----> null
-
数组的其他定义方式
1、声明的同时分配空间
数据类型[] 数组名 = new 数据类型[长度];
int[] a = new int[3];
2,声明的同时初始化(显示初始化)
数据类型[] 数组名 = new 数据类型[]{1,2,3,4...n};
[]不能再指定数组长度,长度由{}中数值个数确定
int[] a = new int[3]{1,3,4}; //error!!!
3,声明的同时初始化(显示初始化)
数据类型[] 数组名 = {数值1,数值2,数值3};
int[] a = {1,2,3}; //数组的长度由{}中数据的个数决定且初始化的内容必须和声明一起进行
-
数组的内存
- 数组在内存中存储空间是连续的
- 数组类型的变量是在栈中存储 —> 在堆空间的首地址 —> 在堆空间申请存放数据的地方
- 数组类型的变量之间可以相互赋值,传递的是数组在堆空间中的首地址。相互赋值的数组类型的变量存储数据类型要一致。
int[] a = {1,2,3,4}; int[] b = a; for(int i = 0; i < b.length; i++){ System.out.print(b[i] + " "); //1 2 3 4 } System.out.println("数组b长度:" + b.length); //4 a[2] = 10; for(int i = 0; i < b.length; i++){ System.out.print(b[i] + " "); // 1 2 10 4 }
-
如果数组作为返回值返回,则返回的是数组在堆空间的首地址。
-
int[] a = new int[3]; 数组首地址 ( a )在栈空间内存放,且a 中只有数组的首地址,数组的数据存放在堆空间。调用时由栈内首地址调用访问堆内存放数据的地方。且a是在main函数的栈帧空间内调用。
-
计算机的寻址方式:访问哪个空间,需要哪个空间的地址。在数组中即首地址 + 下标 * 数据类型的字节数
- 访问数组可以通过a[i];的原因是:数组名中存储了数组在堆空间的首地址,同时指定访问下标,再根据数据类型获知每个空间字节数,又数组地址连续,即可快速获取对应空间的地址。
数组扩容
-
第一种思想:申请一个更大长度的新数组,通常长度为原数组的两倍。将原有数组的元素内容一一赋值到新数组中。
最后新地址覆盖旧地址。( a = b )数组类型地址赋值。
-
第二种:申请一个更大长度的新数组,通常为原数组的两倍。将原有数组元素一一赋值,使用
System.arraycopy( 原数组名 a, 起始下标 i, 新数组名 b , 存储起始下标 j, 拷贝的个数 n);
-
第三种:借助 java.util.Arrays.copyOf(原数组名 a, 新数组长度); 有返回值,需要接收新数组地址。
可变长的参数:使代码灵活度变高—>底层源码时常用
- 即函数的参数不再是固定的个数需求,而是随着调用给定具体个数的实参。
public static 返回值类型 函数名(数据类型 ... 变量名){
//package Day06.upClass5.java
}
-
在函数内部将可变长参数当作数组应用,具有数组的所有应用特点。 如 变量名.length
-
如果函数的形参中出现可变长参数和固定参数,必须将可变长参数定义在最后
-
一个函数中形参可变长参数最多有一个
-
使参数不固定,调用者根据自身需求确定实参个数,使程序更加通用和灵活
排序
- 冒泡排序法bubble sort:将相邻的两个元素一一进行比较,如果前面元素大于后面元素,两者交换位置。
- 选择排序法:每一轮固定一个下标,用此下标中的元素和后面的元素一一进行比较,如果大,则交换。
- 快速排序:java.util.Arrays.sort(数组名); 默认从小到大
二维数组
-
是一维数组的一维数组来实现的,二维数组长度:行数:数组名.leng 列数:数组名[0].length
-
首先根据行数分配一个对应长度的一维数组
-
根据行数对应的一维数组分配多个其他的一维数组
-
定义
- 数据类型[] [] 数组名 = new 数据类型[行数] [列数];
- 数据类型[] [] 数组名 = new int[] []{ {数值,数值} , {数值,数值},…};
- 数据类型[] [] 数组名 = { {数值,数值} ,{数值,数值},{数值,数值}};
-
不规则的二维数组:
int[][] arr = {
{1,2},
{1,2,3},
{1,2,3,4}
};
- 二维数组定义时必须指定行数,可以先不指定列数。
可以在后面使用
a[0] = new int[3];
a[1] = new int[5];
来再定义二维数组的列。