目录
方法
-
什么是方法,有什么用?
方法(method)是可以完成某个特定功能的并且可以重复利用的代码片段。
在C语言中,方法被称为“函数”。在java中,叫做方法。
你定义/抽取一个方法,而这个方法却无法完成某个功能。那么抽取的这个方法毫无意义。一般一个方法就是一个功能单元。
假如在以后的开发中,某个功能是可以独立抽取出来的。建议定义为方法,这样以后只要需要这个功能,那么直接调用这个方法即可,而不需要重复编写业务逻辑代码。
没用方法的求和
/*
对一个java程序来说,如果没有方法,会存在什么问题?
代码无法得到复用。
(提高复用性,可以定义方法,然后需要使用该功能的时候,直接调用方法即可,这样代码就得到复用了)
*/
public class MethodText01 {
//入口主方法
public static void main(String[] args){
//需求1:计算100和200的和
int x = 100;
int y = 200;
int z = x + y;
System.out.println(x+"+"+y+"+"+"="+z);
//需求2:计算666和888的和。
//这个需求实际上与需求1是完全相同的,只不过具体求和时的“数据不同”
int a = 666;
int b = 888;
int c = x + y;
System.out.println(a+"+"+b+"+"+"="+c);
/*
需求1和需求2本质上相同,只不过参与运算的数值不同,代码编写了两遍
代码没有得到重复利用,专业术语叫做:复用性差
功能/业务逻辑既然相同,为什么要重复编写代码
代码能不能只写一次,以后需要再次使用该“业务/需求”的时候,直接调用就可以了、
如果想达到代码复用,需要使用java中的方法。
*/
}
}用了方法的求和
/*
这个程序是个体验程序,体验方法的作用
注意:
程序开始执行的时候是先执行main方法
因为main方法是一个入口
在java语言中所有的方法体中的代码必须遵循自上而下的顺序依次逐行执行
main方法不需要程序员手动调用,是JVM调用的。除了main方法之外的方法都需要程序员手动调用.
方法只有调用的时候才会执行,方法不调用不会执行。
*/
public class MethodText02 {
//方法定义在类体中。
//方法定义的先后顺序没有关系,都可以。
// public static void sumInt(int x , int y) {//自上而下
// int z = x + y;
// System.out.println(x + "+" + y + "=" + z);
// }
public static void main(String[] args){
//需求1:计算100和200的和
sumInt(100,200);
//需求2:计算666和888的和
sumInt(666,888);
//需求3:计算111和222的
sumInt(111,222);
}
//在这个类体中定义一个方法,这个方法专门用来求和。
//x y z 在以下的sumInt方法中都属于局部变量
//局部变量有一个特点:方法结束之后,局部变量占用的内存会自动释放。
public static void sumInt(int x , int y){//自上而下
int z = x + y;
System.out.println(x+"+"+y+"="+z);
}
} -
方法怎么定义,语法机制是什么?
1、方法怎么定义,语法机制是什么?
[修饰符列表] 返回值类型 方法名(形式参数列表){
方法体;
}
方法定义之后需要调用,不调用不会执行。
注意:[]中括号中的内容不是必须的,是可选的。方法体由java语句构成。
1.1、关于修饰符列表:
修饰符列表不是必选项,是可选的。目前为止,统一写成:public static 以后就知道应该怎么写了
1.2、关于返回值类型
第一:返回值类型可以是任何类型,只要是java中合法的类型就行。
数据类型包括基本数据类型和引用数据类型。也就是说,返回值类型可以是:
byte、short、int、long、float、double、boolean、char、String·····
第二:什么是返回值
返回值一般指的是一个方法执行之后的结果。
结果通常是一个数据,所以被称为“值”,而且还叫“返回值”。
方法就是为了完成某个特定的功能,方法结束之后大部分情况都是有一个结果的
而体现结果的一般都是数据,数据要有类型,这就叫做返回值类型。
main(){
//调用a方法
//a();··如果a方法执行结束之后有返回值,这个返回值返回给main。
}
a(){java语句;...}
方法执行结束之后的返回值实际上是给调用者,谁调用就返回给谁。
第三:当一个方法执行结束,不返回任何值的时候,返回值类型也不能空白。要写上void关键字
所以void表示该方法执行结束后不返回任何结果。
第四:如果返回值类型不是void,那么在方法执行结束时必须用“return 值;”这样的语句来完成“值”的返回
如果没有“return 值;”,编译器会报错。
return 值; 语句作用:返回值(即返回方法的执行结果)
第五:只要有“return”关键字的语句执行,当前方法必然结束。
第六:如果返回值类型是void,那么在方法中不能有“return 值;”这样的语句
但是可以有“return;”语句,这个语句的作用是:终止当前方法。
第七:除了void之外,剩下的都必须有“return 值;”这样的语句
1.3、方法名
方法名见名知意。(驼峰命名方式)
方法名在标识符命名规范中,要求首字符母小写,后面每个的单词首字母大写。
只要是合法的标识符就行。
1.4、形式参数列表
简称:形参
注意:形式参数列表中的每一个参数都是“局部变量”,方法结束之后内存释放
形式参数的个数是:0~N个
public static void main(){}
public static void main(int x){}
public static void main(int x , int y){}
public static void main(int a, int b,double d,String s){}
形式有多个的话用英文状态下的逗号隔开“,”
形参的数据类型起决定性作用,形参对应的变量名是随意的。
1.5、方法体:
由java语句构成。java语句以“;”结尾。
方法体中编写的是业务逻辑代码,完成某个特定功能。
在方法体中的代码是遵循自上而下的顺序依次逐行执行
在方法体中处理业务逻辑代码的时候需要数据,数据来源就是这些形参。
2、方法定义之后怎么调用呢?
方法必须调用才能执行。
如何调用,语法是什么?
- 类名.方法名(实际参数列表);//这里的点相当于的,表示调用xx类体里的xx方法
- 实参和形参的类型必须一一对应,个数也要一一对应。public class MethodText03 {
//main方法结束后,不需要给JVM返回任何执行结果
public static void main(String[] args){
//调用方法
//错误:不兼容的类型:String无法转换为int
//MethodText03.divide("abc",200);//这里的a是:int a="abc"
//错误:(80, 21) java: 无法将类 MethodText03中的方法 divide应用到给定类型;
// 需要: int,int
// 找到: 没有参数
// 原因: 实际参数列表和形式参数列表长度不同
// MethodText03.divide();
//( 10 , 2 )叫做实际参数列表,简称实参。
//注意:实参和形参必须一一对应,包括类型和个数。
MethodText03.divide(10,2);
//调用sum方法
//怎么接收这个方法的返回结果??
//使用变量来接收这个方法的返回值。 注意变量的数据类型要与所调用方法的类型一致
//MethodText03.sum(100,200);
int result =MethodText03.sum(100,200);
System.out.println(result);//300
//result变量可以是double类型吗?
//double是大容量。int是小容量。这里是自动类型转换:大--->小
double result2=MethodText03.sum(100,200);
System.out.println(result2);//300.0
//对于没有返回值的方法,变量能接收吗?
//divide方法结束没有返回值,不能接收。
//错误:不兼容的类型: void无法转换为int
//int i= MethodText03.divide(100,2);
//当一个方法有返回值的时候,我可以选择不接收吗?
//值会返回,但是可以选择不接收。可以不用变量接收,但是这个返回值存在
//不过这样没意义,一般程序返回了执行结果,都是需要接收这个结果的。
//以下代码虽然没有使用变量接收这个返回值,但是这个值还是返回了。
//返回之后内存马上释放,因为没有使用变量接收。
MethodText03.sum(100,200);
byte b1 =10; //int a= b1
byte b2=20;
int result3=sum(b1,b2);//自动类型转换
System.out.println(result3);
}
public static int sum(int a,int b){
return a+b;
}
//业务/需求:计算两个int类型数据的商。
//缺少返回语句
/*
public static int divide(int x ,int y){
int z= x/y ;
}
*/
//不兼容的类型: String无法转换为int
/*
public static int divide(int x ,int y){
int z= x/y ;
return "abc" ;
}
*/
//正确的
/*
public static int divide(int x ,int y){
int z= x/y ;
return z ;
}
*/
//也可以这样写
/*
public static int divide(int x ,int y){
return x/y ;
}
*/
//如果我不需要执行结束之后的返回值,而是希望直接输出
//错误:不兼容的类型: 意外的返回值
/*
public static void divide(int x ,int y){
return x/y ;
}
*/
//可以
/*
public static void divide(int x ,int y){
return;//用来中止这个方法的
}
*/
//可以
/*
public static void divide(int x ,int y){}
*/
public static void divide(int a, int b){
System.out.println(a/b);
}
} -
如果两个方法在同一类中,”类名. “可以省。不在同一类中,不能省
/*
方法调用时
a方法调用b方法时,a、b方法在同一个类中,“类名.”可以省略
如果不在同一个类中,“类名.不能省”
*/
//类1
public class MethodText04 {
public static void daYin3(){
System.out.println("hello world333!!");
}
public static void main(String[] args){
//调用dayin方法
MethodText04.daYin();
MethodText04.daYin2();
MethodText04.daYin3();
//“类名.”可以省略吗
daYin();
daYin2();
daYin3();
//跨类调用方法,前面一定要有“类名.”
MyClass.daYin();
MyClass.daYin2();
}
public static void daYin(){
System.out.println("hello world");
}
public static void daYin2(){
System.out.println("hello world2!!!");
}
}
//类2
class MyClass{
public static void daYin(){
System.out.println("打印");
}
public static void daYin2(){
System.out.println("打印222");
}
public static void daYin3(){
System.out.println("打印333");
}
} -
不是只有main方法中才能调用方法。任何一个方法都可以
/*
任何一个方法体当中的代码都是遵循自上而下的顺序依次逐行执行的
推测执行结果:
main begin
m1 begin
m2 begin
m3 begin
T's m3 method execute!
m3 over
m2 over
m1 over
main over
main方法最先执行,并且main方法是最后一个结束。
main方法结束,整个程序就结束了。
*/
public class MethodText05 {
public static void main(String[] args){
System.out.println("main begin");
//调用m1方法
m1();
System.out.println("main over");
}
public static void m1(){
System.out.println("m1 begin");
//调用程序不一定写到main方法中,不要把main方法特殊化
//main方法也是个方法
m2();
System.out.println("m1 over");
}
//m2方法可以调用T类的m3()方法吗?
public static void m2(){
System.out.println("m2 begin");
T.m3();
System.out.println("m2 over");
}
}
class T{
public static void m3(){
System.out.println("m3 begin");
System.out.println("T's m3 method execute!");
System.out.println("m3 over");
}
} -
break 和 return 的区别
/*
break; 语句 和 return; 语句有什么区别?
break; 终止switch和离他最近的循环
return; 用来终止离他最近的一个方法。
*/
public class MethodText06 {
//main方法返回值类型是void,表示没有返回值。
public static void main(String[] args){
for(int i=0;i<10;i++){
if(i==5){
break;//终止for循环;
// return;//终当前的方法
//错误,不兼容的类型:意外的返回值。
//return 10;
}
System.out.println("i="+i);
}
System.out.println("Hello World!");
}
} -
同一个域中,return语句下面不能再编写其他代码,因为执行不到。
/*
同一个域当中,“return语句”下面不能再编写其他代码
*/
public class MethodText07 {
public static void main(String[] args){
//调用m1方法
int result =m();
System.out.println(result);//1
//调用m2方法
int result2= m2(true);
System.out.println(result2);//1
//再次调用m3方法
int result3=m2(false);
System.out.println(result3);//1
}
//以下程序报错,编译器只检查语法,他不知道flag是true还是false。所以觉得返回语句return可能不会执行
/*
public static int m() {
boolean flag = true;
if (flag) {
//编译器觉得这行代码可能不会执行
//为了确保程序不出现异常,错误:缺少返回语句
return 1;
}
}
*/
//同一个域当中,“return语句”下面不能再编写其他代码,编写之后编译爆错
public static int m() {
boolean flag = true;
if (flag) {
//编译器觉得这行代码可能不会执行
//为了确保程序不出现异常,错误:缺少返回语句
return 1;
//错误:无法访问的语句
//System.out.println("hello1");
}
System.out.println("hello2");
return 2;
//错误:无法访问的语句
//System.out.println("hello3");
}
//三目运算符 有时会让代码更简练
public static int m1(){
boolean flag=true;
return flag ? 1 : 0;
}
//带有一个参数的方法
public static int m2(boolean flag){
return flag ? 1 : 0;
}
} -
JVM中主要的三块内存空间
-
栈数据结构
-
方法执行过程中的内存变化
/*
局部变量: 只在方法体中有效,方法结束之后,局部变量的值就释放了。
JVM三块主要的内存: 栈内存、堆内存、方法区内存
方法区最先有数据: 方法区中放代码片段。存放class字节码。
堆内存: 后面讲
栈内存: 方法调用的时候,该方法需要的内存空间在栈中分配。
方法不调用是不会分配空间的。
方法只有在调用时,才会在栈中分配空间,并且调用时就是压栈。
方法执行结束之后,该方法所需的空间就会释放,此时发生弹栈动作
方法调用叫做: 压栈 分配空间
方法结束叫做: 弹栈 释放空间
栈中存储什么?
方法运行过程中需要的内存,以及栈中会存储方法的局部变量。
*/
public class MethodText08 {
//主方法,入口
public static void main(String[] args){
//int a = 100;
//int b = a;
//这个赋值原理:将a变量中保存的100这个数字复制一份传给b变量
//所以a和b是两个不同的内存空间
System.out.println("main begin");
int x= 100;
m1(x);
System.out.println("main over");
}
public static void m1(int i){//i是局部变量
System.out.println("m1 begin");
m2(i);
System.out.println("m1 over");
}
public static void m2(int i){
System.out.println("m2 begin");
m3(i);
System.out.println("m2 over");
}
public static void m3(int i){
System.out.println("m3 begin");
System.out.println(i);
System.out.println("m3 over");
}
} -
用方法实现n的阶乘,例如5的阶乘是:1x2x3x4x5
思考:这个方法应该起什么名字,这个方法的形参是什么,方法的返回值类型是什么。
public class MethodText09 {
public static void main(String[] args){
System.out.print("请输入一个正整数:");
java.util.Scanner s = new java.util.Scanner(System.in);
int num=s.nextInt();
//调用方法计算阶乘。
int jieguo= jieCheng(num);
System.out.println(jieguo);
}
//计算某个数的阶乘,这个数是不确定的,所以我们可以定义形参类型为int
//最终需要一个结果,所以要有返回值。将结果返回给调用方。谁调用,返回给谁,返回值类型定义为int
//我这个方法可以计算任何数的阶乘。
public static int jieCheng(int i){
int result=1;
for(int j=i;j>1;j--){
result *= j;
}
return result;
}
} -
质数判断,以及代码简化
/*
编写一个方法:输出大于某个正整数n的最小质数
质数判断:除了1和本身不能整除其他数
*/
//有注释的在下面
public class MethodText10 {
public static void main(String[] args){
System.out.print("请输入一个正整数,将以这个整数向上求质数:");
java.util.Scanner s=new java.util.Scanner(System.in);
int n= s.nextInt();
minZhiShu(n);
}
//这里简化以下方法:
// public static void minZhiShu(int n) {
// while (true) {
// n++;
// if (isZhiShu(n)) {
// 观察这里,只有是质数的时候才会输出n,所以不是质数的时候要一直循环,而while只有true才会一直循环
// 所以用!isZhiShu(n)来让while循环,不是质数的!=继续循环 是质数的!=结束循环
// 结束循环之后输出质数,所以输出语句在循环外,因为是这个数向上求质,所以++n,先赋值后运算
// while(!isZhiShu(++n)){} 输出语句 即以下方法
// System.out.println(n);
// break;
// }
// }
// }
public static void minZhiShu(int n){
while (!isZhiShu(++n)) {
}
System.out.println(n);
}
public static boolean isZhiShu(int num){
for(int i=2;i<num;i++){
if(num % i ==0){
return false;
}
}
return true;
}
}
//有注释版
//public class MethodText10 {
//
// public static void main(String[] args){
// System.out.print("请输入一个正整数,将以这个整数向上求质数:");
// java.util.Scanner s=new java.util.Scanner(System.in);
// int n= s.nextInt();
// minZhiShu(n);
//
// //以下再编写一个方法代替
// /*
// int n=10;
// while(true){
// n++;//因为这个数要比n大,所以循环里第一行就让他执行+1.
// //这里调用下面判断质数的方法,返回值是boolean类型,这里定义一个变量引用这个方法
// Boolean flag=isZhiShu(n);//判断此时的n是否为质数
// if(flag){
// System.out.println(n);//如果是输出这个数字。
// break;//因为只要一个数,所以输出后结束循环
// }
// }
// */
// /*对判断质数的方法进行测试:
// boolean flag = isZhiShu(13);
// System.out.println(flag ? "质数":"非质数");
//
// 以上代码的简化:因为isZhiShu方法的返回值为boolean类型,而三目运算符
// System.out.println(isZhiShu(13) ? "质数":"非质数")
// */
//
// }
//
// //定义一个方法,专门用来判断大于n的最小质数
// //n是这个数,判断比n大的数里,最小的质数
// public static void minZhiShu(int n) {
// while (true) {
// n++;
// //这里调用下面判断质数的方法
// if (isZhiShu(n)) {//这里调用判断指数方法的返回值。
// System.out.println(n);//如果是输出这个数字。
// break;//因为只要一个数,所以输出后结束循环
// }
// }
// }
//
// //定义一个专门的方法,来判断某个数字是否为质数
// //这个方法的形参:被判断的数字num
// //这个方法得返回值类型是boolean true表示是质数,false表示非质数。
// public static boolean isZhiShu(int num){
// for(int i=2;i<num;i++){//除了1和自身不用判断,剩下的数一个一个求余数。
// if(num % i ==0){//只要有一个数被整除,就不是质数
// return false;//不是质数,返回false
// }
// }
// return true;//是质数的 返回true
// }
//}
//自己写的 没有简化
/*
public class MethodText10 {
public static void main(String[] args){
//输出需要判断的数
System.out.print("请输入一个正整数,将以这个整数向上求质数:");
java.util.Scanner s=new java.util.Scanner(System.in);
int n=s.nextInt();
minZhi(n);
}
public static void minZhi(int n){
//首先要比n大,然后一有质数输出然后结束。
//使用do···while来做
do{
n++;//这里因为是要大于n,所以从n+1开始判断。每次执行之前加1
boolean flag =true;//定义一个布尔变量,默认为true
for(int i=2;i<n;i++){//判断质数,从2开始除,除了1和自身剩下的都取余数
if(n % i==0){//能整除的说明不是质数,为false
flag = false;
break;//只要有一个被整除,说明这个数不是质数,结束循环
}
}
if(flag){
System.out.println(n);
return;
}
}while(n>0);
}
// public static void minZhi(int n){
//
// //首先要比n大,然后一有质数输出然后结束。
//
// for(n++;n>0;n++){//首先判断的数应该大于n,然后一个一个的判断,直到出现质数为止。
初始表达式执行一次后判断布尔表达式,这里因为是要大于n,所以从n+1开始判断。
// boolean flag =true;//定义一个布尔变量,默认为true
// for(int i=2;i<n;i++){//判断质数,从2开始除,除了1和自身剩下的都取余数
// if(n % i==0){//能整除的说明不是质数,为false
// flag = false;
// break;//只要有一个被整除,说明这个数不是质数,结束循环
// }
// }
// if(flag){
// System.out.println(n);
// return;
// }
// }
//
// }
}
*/
方法重载
-
不使用方法重载的缺点
/*
方法重载机制
以下代码没有使用方法重载,有什么缺点?
sumInt、sumLong、sumDouble 功能不同,但是功能相似
分别起了三个不同的名字
两个缺点:1、代码不美观【次要】
2、程序员需要记忆更多的方法名称,程序员比较累
*/
public class overloadText01 {
public static void main(String[] args){
System.out.println(sumInt(10,20));
System.out.println(sumLong(10L,20L));
System.out.println(sumDouble(10.0,20.0));
}
public static int sumInt(int a,int b){
return a+b;
}
public static long sumLong(long a,long b){
return a+b;
}
public static double sumDouble(double a,double b){
return a+b;
}
} -
方法重载的优点体验
/*
使用方法重载机制,解决之前的两个缺点
优点1:代码整齐美观。
优点2:“功能相似”的,可以让“方法名”相同,更易于以后的代码编写。
在java语言中,是怎么进行方法区分的呢?
首先,java编译器会通过方法名进行区分。
但是在java语言中允许方法名相同的情况出现。
如果方法名相同的情况下,编译器会通过方法名的参数类型进行方法的区分。
*/
public class OverloadText02 {
public static void main(String[] args){
System.out.println(sum(10,20));
System.out.println(sum(10L,20L));
System.out.println(sum(10.0,20.0));
}
public static int sum(int a,int b){
System.out.println("int求和:");
return a+b;
}
public static long sum(long a,long b){
System.out.println("long求和:");
return a+b;
}
public static double sum(double a,double b){
System.out.println("double求和:");
return a+b;
}
} -
方法重载机制详解
/*
方法重载(overload)
什么时候需要考虑使用方法重载?
在同一个类当中,如果“功能1”和“功能2”他们的功能是相似的,那么可以考虑将他们的方法名一致
,这样代码既美观,又便于后期的代码编写(容易记忆,方便使用)
什么时候代码会发生方法重载?
主要靠区分方法名和形参
条件1:在同一个类当中
条件2:方法名相同
条件3:参数列表不同
参数的 个数 不同算不同
参数的 类型 不同算不同
参数的 顺序 不同算不同
只要同时满足以上三个条件,那么我们可以认定方法和方法之间发生了重载机制
注意:
不管代码怎么写,最终一定能让java编译器很好的区分开这两个方法
方法重载与方法的“返回值类型”无关
方法重载与方法的“修饰符列表”无关
*/
public class OverloadText03 {
public static void main(String[] args){
//个数不同
m1();
m1(100);
//顺序不同
m2(10,10.0);
m2(10.0,10);
//类型不同
m3(10);
m3(11.2);
}
public static void m1(){
System.out.println("m1无参数的执行");
}
public static void m1(int a){
System.out.println("m1有一个int参数的执行");
}
//方法名相同,顺序不同
public static void m2(int x ,double y){
System.out.println("xy");
}
public static void m2(double y,int x){
System.out.println("yx");
}
//类型不同
public static void m3(int a){
System.out.println("1");
}
public static void m3(double a){
System.out.println("2");
}
//这里不是方法重载,而是方法重复。因为变量类型是一样的,方法名也是一样的,所以编译不能通过
// public static void m4(int x,int y){
//
// }
// public static void m4(int a,int b){
//
// }
//这两个方法没有发生重载,而是重复。这个方法虽然返回值类型不同,但是返回值可以选择不接收
//编译器识别方法重载主要靠方法名和形参,而返回值类型与形参并没有关系,只是返回一个值
//所以方法重载与返回值类型没有关系
// public static int m5(){ return 1;}
// public static double m5(){ return 1.5; }
//修饰符列表不是必须的,是可选的。方法重载与修饰符列表无关
// void m6(){}
// public static void m6(){}
}
class MyTwoClass{
//不在同一个类中,不能叫做方法重载
public static void m1(int x,int y){
}
} -
、我们一直使用的print()其实是一个方法,并且是方法重载
public class OverloadText04 {
public static void main(String[] args){
//调用m方法
m(100);//()前面的m是一个方法名
System.out.println(10);
System.out.println(3.14);
System.out.println(true);
System.out.println("a");
System.out.println("abc");
//所以这里推算println是一个方法名,但这个方法是谁写的?
//SUN公司的java团队,直接调用就可以。我们只需要记忆一个方法名就可以
//参数类型可以随便传,所以println()方法肯定是重载了。
}
public static void m(int x){
}
} -
System.out.println();的重载,简化输出语句
public class S {
//以下所有的p()方法构成了方法的重载
//换行的方法
public static void p(){
System.out.println();
}
//输出byte
public static void p(byte b){
System.out.println(b);
}
//输出short
public static void p(short s) {
System.out.println(s);
}
//输出int
public static void p(int i) {
System.out.println(i);
}
//输出long
public static void p(long l) {
System.out.println(l);
}
//输出float
public static void p(float f) {
System.out.println(f);
}
//输出double
public static void p(double d) {
System.out.println(d);
}
//输出boolean
public static void p(boolean b) {
System.out.println(b);
}
//输出char
public static void p(char c) {
System.out.println(c);
}
//输出String
public static void p(String s) {
System.out.println(s);
}
}
方法递归
-
什么是方法递归
/*
方法递归?
1、什么是方法递归?
方法自己调用自己,就叫做方法递归
2、当递归时程序没有结束条件,一定会发生:
栈内存溢出错误:stack Over flow Error
所以:递归必须要有结束条件。(这是非常重要的知识点。)
JVM发生错误之后只有一个结果,就是退出JVM
3、假设递归是有结束条件的, 就一定不会发生栈内存溢出吗?
假设这个结束条件是对的,是合法的,递归有的时候也会出现栈内存溢出错误
因为可能递归的太深,栈内存不够了,因为一直在压栈。
4、在实际的开发中,不建议轻易的选择递归,能用for循环while循环代替的,尽量使用
循环来做,因为循环的效率高,耗费的内存极少。递归耗费的内存比较大,另外递归的
使用不当,会导致JVM死掉(但在极少数的情况下,不用递归,这个程序没法实现)
5、在实际的开发中,如果遇到了栈内存溢出错误,应如何解决?
首先 :
检查递归的结束条件对不对,如果递归结束条件不对。必须修改,直到正确为止
第二步:假设递归条件没问题
这个时候需要手动的调整JVM的占内存初始化大小。可以将栈内存的空间调大一些
第三步:
调整了大小,如果运行时还是出现这个错误,只能继续扩大栈的内存大小
在dos中用(java-x)可查看调整堆栈大小的参数
设置java线程堆栈大小
java -Xss xxxGB/MB xx.java
*/
public class RescursionText01 {
//入口
public static void main(String[] args){
doSome();
}
public static void doSome(){
System.out.println("doSome begin");
//调用方法:doSome()既然是一个方法,那么doSome方法可以调用吗?当然可以。
//目前的递归是没有结束条件的,会出现什么问题?
doSome();
//这行代码永远执行不到
System.out.println("doSome over");
}
/* 相当于一直执行以下代码
public static void doSome(){
System.out.println("doSome begin");
doSome();
}
public static void doSome(){
System.out.println("doSome begin");
doSome();
}
public static void doSome(){
System.out.println("doSome begin");
doSome();
}
public static void doSome(){
System.out.println("doSome begin");
doSome();
}
public static void doSome(){
System.out.println("doSome begin");
doSome();
}
public static void doSome(){
System.out.println("doSome begin");
doSome();
}
*/
} -
使用递归计算1~n的和
//先用循环编写,计算1~n的和
public class RecursionText02 {
public static void main(String[] args){
//1~10的和
int retValue1 = sum(10); //定义一个变量接收返回值
System.out.println(retValue1); //55
//1~3的和
int retValue2=sum(3);
System.out.println(retValue2); //6
}
//单独使用一个方法计算1~n的和
// public static int sum(int i){
// int result=0;
// for(int j=1;j<=i;j++){
// result += j;
// }
// return result;
// }
//使用递归
// 3 + 2 + 1
public static int sum(int n){
//n最初等于3
//3 + 2(2为n-1)
//sum(n-1);//sum(2)//sum(1)
//n=1的时候递归结束,如果n就是1的话直接返回1
if(n ==1){
return 1;
}
//程序执行到这里说明n不是1
//n + sum(n-1)
//3 + sum(2) //2+sum(1)
// sum(1)的时候返回1,返回给调用它的那个方法,然后继续往前返回
return n+sum(n-1);//n + sum(n-1)这个是返回值,跟在return后面直接返回
}
} -
使用递归计算n的阶乘
//使用递归计算n的阶乘
public class RecursionText03 {
public static void main(String[] args){
int n=11;
int jieGuo= jieCheng(n);
System.out.println(jieGuo);
System.out.println(jieCheng2(n));
}
//使用递归
public static int jieCheng(int n){
if(n==1){
return 1;
}
return n * jieCheng(n-1);
}
//使用for循环
public static int jieCheng2(int n){
int result = 1;
for(int j=2;j<=n;j++){
result *=j;
}
return result;
}
} -
判断两个数/三个数的大小,要求利用方法重载 ,以及方法要重复使用
public class RecursionText04 {
public static void main(String[] args){
int result1 = bigerNum(10,30);
System.out.println(result1);
int result2 = bigerNum(55,34,23);
System.out.println(result2);
}
//定义一个方法,判断两个数的大小
public static int bigerNum(int a,int b){
return a>b ? a:b;//
}
//在上一个方法的基础上,继续判断第三个数的大小
public static int bigerNum(int a,int b,int c){
return bigerNum(a,b)>c ? bigerNum(a,b):c;
//先比较两个数,再用大的那个与相比较
// 如果那个较大的数大于c,则输出比较大的那个,如果小于,就是c最大,输出c
//因为这里两个数哪个大我们并不清楚,所以这里直接调用判断两个数哪个大的方法
}
}