1.方法:
1.1 概述和作用
* 方法:就是一堆代码的集合,一般一个方法用于完成一个特定的功能(只保证功能的实现,最终用在什么地方,与声名无关)
* 优点:代码复用,易维护,易扩展,灵活性高
1.2 方法的声名
* 修饰符列表 返回值类型 方法名 (参数列表){
* 方法体
* }
* 修饰符列表:可以有,也可以没有,可以有多个,用空格隔开,不区分顺序
* 权限修饰符:public,protected,private,默认(四选一)
* 返回值类型:可以为十一种数据类型中的任何一种,没有返回值可以写void
* 方法名:符合命名规则即可
* 参数列表:可以没有,也可以有多个,中间用逗号隔开,参数列表中的变量也是局部变量
* 方法体:方法中的功能代码
* return:中止方法运行,并返回结果,如果方法中有返回值类型,则必须有return语句
* 如果方法中没有返回值类型,return则可写可不写,如果写了return则只是中止方法运行,不会返回数据
1.3 方法的分类
* 成员方法:没有使用static修饰的方法
* 静态方法:使用static修饰的方法
* 构造方法:之后再说
//无参无返回值的静态方法
public static void m1() {};
//有参无返回值的静态方法
public static void m2(int a) {};
//多参无返回值的静态方法
public static void m3(int a,double b) {};
//有参有返回值的静态方法
public static int m4(int a,int b) {
return 10;
};
//有参无返回值的成员方法
public void m5(int a) {};
1.4 方法调用
* 静态方法:类名.方法名(参数) 同一个类中可以省略类名
* 成员方法:对象.方法名(参数)
public static void main(String[] args) {
//注意:方法不调用不执行,调用才执行,并把结果返回给调用出处,所以不需要考虑方法声名的先
//后顺序
Method_01.m1();
//当前类中类名可忽略
m1();
//如果方法中有参数,则我们调用时,必须传入对应的数据(类型和个数都要对应)
m2(2);
//如果我们调用有返回值的方法,我们一般需要一个变量来接受返回值
int restlt = m4(1,2);
}
1.5 入参和出参
* 形参:形容参数,方法声名时,指定的参数列表,称为形参
* 实参:实际参数,调用方法时传入的具体参数
* 入参:参数列表,调用方法时需要传入的数据
* 出参:返回值,方法执行时需要返回的数据
1.6 方法重载
* Overload:方法重载
* 方法名相同,参数列表不同,就是方法重载
* 参数列表不同分为两种
* 1.参数个数不同
* 2.参数类型不同
* 优点:功能相同,名字相同,方便记忆,代码美观
public class Method_03 {
public static void main(String[] args) {
sumInt(10,20);
sumDouble(10.2,20.8);
sumLong(22L,13L);
//重载之后
sum(12,10);
sum(11.0,12.0);
sum(13L,98L);
//以下也是方法的重载
System.out.println("你好");
System.out.println(12);
System.out.println(12.9);
System.out.println(false);
}
public static void sumInt(int a,int b) {
System.out.println(a+b);
}
public static void sumDouble(double a,double b) {
System.out.println(a+b);
}
public static void sumLong(Long a,Long b) {
System.out.println(a+b);
}
//重载后
public static void sum(int a,int b) {
System.out.println(a+b);
}
public static void sum(double a,double b) {
System.out.println(a+b);
}
public static void sum(Long a,Long b) {
System.out.println(a+b);
}
}
1.7 方法调用时类型转换
public static void main(String[] args) {
//自动类型转换、
//由于前面是double,所以后面的9会转换为double,匹配double对应的方法
m1(1.5,7);
//由于两个都是int,所以转换为long,而不是double
m1(1,2);
}
public static void m1(long a,long b) {
System.out.println("long...");
}
public static void m1(double a,double b) {
System.out.println("double...");
}
2.内存分析
* JVM运行时区域
* 程序计数器:暂时不管
* 静态区/方法区:用来保存运行时的class文件和静态属性和方法的
* VM栈:是以栈数据结构为模型,开辟一块空间,先进后出
* 用于执行方法,每一个方法的调用,就是一个栈帧,一般main方法为栈底元素
* 方法调用就是等于压栈,方法执行完成就等于出栈
*
* 栈帧:在栈内存中保存的数据空间
* 栈底元素:第一个放入栈空间的栈帧
* 栈顶元素:最后一个放入栈空间的栈帧
* 压栈:把栈帧放入栈空间的过程
* 弹栈:把栈帧在栈空间弹出的过程
* 堆内存:用于保存对象
* 本地方法栈:和VM栈一样,只不过用于执行本地方法
3.递归
3.1 概述和基本应用
* 递归:递归就是在方法中调用当前方法
* 直接递归:当前方法中对自身方法进行调用
* 间接递归:A方法调用B方法,B方法调用A方法
* 递归和迭代:递归和迭代是等价的,都需要中止条件,否则就是死循环
* 报错:java.lang.StackOverflowError:栈内存溢出,一般是因为一直压栈没有弹栈导致
* 原因:1.递归没有中止条件,出现死循环
* 2.递归代码没有问题,但是因为要计算的功能比较大,导致压栈过多
* 注:递归比较消耗内存,效率较低,所以能用循环解决的问题一般不适用递归,循环能做的递归一定能做,但是递归能做的循环不一定能做
* 一般树状结构一类的,循环做不了,需要使用递归去做,如文件夹的嵌套关系(例如:要获取某文件夹下所有的文件包含子文件)
public static void main(String[] args) {
m1();
}
//直接递归
public static void m1() {
m1();
}
//间接递归
public static void m2() {
m3();
}
public static void m3() {
m2();
}
3.2 计算1~n的加加
//递归做
public static int test1(int n) {
if(n == 1) {
return 1;
}
return n + test1(n-1);
}
//循环做
public static int test2(int n) {
int sum = 0;
for(int i = 1;i <= n;i++) {
sum+=i;
}
return sum;
}
3.3 斐波那契数列
/*
* 前两位是1,后续每一位都是前两位的和
* 1 1 2 3 5 8 13
*/
public static int test(int n) {
if(n == 1 || n == 2) {
return 1;
}else {
return test(n-1) + test(n-2);
}
}
public static void main(String[] args) {
int result = test(10);
System.out.println(result);
}