关于方法,先不说方法是什么,先来看没有使用方法写的代码所存在的问题
- 以下代码都是完成两int类型数据的求和,相同的代码写了三遍(只不过每次参与运算的数据不同),代码没有得到重复利用
- 应该在Java中存在一种机制:
实现某个功能的代码只要写一遍
要使用这个功能,只需要把具体的数据传递给它
这个功能完成后返回一个最终结果
这样一来,代码就能得到重复利用,提高代码复用性【这就是“方法”】
public class MethodTest01{
public static void main(String[] aegs){
//需求1:编写代码,计算10和20的和,输出结果【功能:计算两个int类型数据的和】
int a = 10;
int b = 20;
int c = a+b;
System.out.println(a+"+"+b+"="+c);
//需求2:编写代码,计算666和888的和,输出结果【功能:计算两个int类型数据的和】
int x = 666;
int y = 888;
int z = x+y;
System.out.println(x+"+"+y+"="+z);
//需求1:编写代码,计算10和20的和,输出结果【功能:计算两个int类型数据的和】
int m = 111;
int n = 222;
int e = m+n;
System.out.println(m+"+"+n+"="+e);
}
}
上述三个需求其实就是一个需求
需求为:计算两个int类型数据的和,功能相同,只不过每次参与运算的数据不相同。
针对第一个例子使用方法效果
以下直接使用方法【不讲语法】,分析优点
- 代码得到重复利用
方法的本质是什么?
- 方法实际上就是一段代码片段,并且这段代码片段可以完成某个特定功能,并且可以被重复利用
方法:Method 调用:invoke
方法在c语言中叫做函数:Function
方法定义在类体中,在一个类当中可以定义多个方法,方法编写的位置没有先后顺序,可以随意。
方法体中不能再定义方法!!!!!!!!!!
方法体由Java语句构成,方法体中代码遵循由上而下的顺序依次执行。
public class MethodTest02{
public ststic void main(String[] args){
//计算两个int类型数据的和
MethodTest02.sumInt(10,20);
MethodTest02.sumInt(666,888);
MethodTest03.sumInt(111,222);
}
//定义一个方法
//该方法完成计算两个int类型数据的和,并且将结果输出
public static void sumInt(int a,int b){
int c = a+b;
System.out.println(a+"+"+b+"="c);
}
}
关于Java语言中的方法
1 方法怎么定义,语法结构
[修饰符列表] 返回值类型 方法名(形式参数列表){
方法体;
}
2 对以上名词进行解释说明
2.1 修饰符列表
- 可选项,不是必须的
- 现阶段,统一写成:public static【以后再解释】
- 方法的修饰符列表有“static”关键字,怎么调用这个方法
类名.方法名(实际参数列表);
2.2返回值类型
-
什么是返回值
一个方法是可以完成某个特定功能的,这个功能结束后,大多数都是需要返回最终执行结果的,执行结果可能是一个具体存在的数据,而这个具体存在的数据就是返回值。 -
返回值类型
返回值是一个具体存在的数据,是数据就表示它一定有类型,此处需要对返回值具体类型进行指定 -
返回值类型都可以指定哪些呢
java任意一种类型都可以,包括基本数据类型和所有的引用数据类型 -
需要值得注意的是,可能这个方法执行结束后不返回任何数据。java中规定,当一个方法执行结束后不返回任何数据的话,返回值类型必须编写: void关键字
-
返回值类型可以是:byte、short、int、long、float、double、boolean、char、String、void…
-
返回值如果不是void,即表示这个方法执行结束后必须返回一个具体数据,当方法执行结束后没有返回任何数据的话,编译会报错。怎么返回值呢?
代码这样写:“return 值;”,并且要求这个“值”的类型必须和“方法的返回值类型”保持一致,不然编译报错 -
返回值类型如果是void,在方法体中不能编写“return 值;”这种语句,但是要注意,可以编写“return;”
这种语句 -
不论是“return;”还是“return 值;”,只要有“return”关键字的语句一执行,return所在的方法结束【不是JVM结束,只是return所在的方法结束】
2.3方法名
- 合法标识符
- 方法名最好见名知意
- 方法名最好是动词
- 方法名首字母小写,后面每个单词首字母大写
2.4形式参数列表:简称形参
- 形参是局部变量:int a; double b; float c; String s;…
- 形参的个数:0~N个
- 多个形参之间用“逗号”隔开
- 形参中起决定性作用的是形参的数据类型,形参的名字就是局部变量名字
- 方法在调用的时候,实际给这个方法传递的真实数据被称为:实际参数,简称:实参
- 实参列表和形参列表必须满足:
-数量相同
-类型对应相同
例如:
方法定义
public static int sum(String 变量,int 合法标识符){ //(int a,int b)是形参列表
}
方法调用
sum(“abc”,“def”);编译报错!
sum(“123”,20); //(“123”,20)是实参列表
这里总结一个小技巧有的新手总是不能理解和区分形参和实参,这里只要记住一点,凡是带有数据类型修饰的就一定是形参!!
2.5.方法体
方法体必须由大括号括起来,方法体中的代码有顺序,遵循自上而下的顺序依次执行
方法体由java语句构成,每一个java语句以“;”结尾
3.方法怎么调用?
【方法只定义而不去调用是不会执行的,只有在调用时才会执行】
语法规则:《修饰符列表有static关键字》
类名.方法名(实参列表); //这是一条java语句,表示调用某个类的某个方法,传递这样的实参。
//public表示公开的
//class表示定义类
//MethodTest03是一个类名
public class MethodTest03{//表示定义一个公开的类,起名MethodTest03,由于是公开的类,所以名称要和源文件名称一致。
//这里是类体啦
//类体中不能直接编写java语句,除声明变量之外
//方法出现在类体中
//方法
//public表示公开的
//static表示静态的
//void表示方法执行结束后不返回任何数据
//main是方法名:主方法
//(String[] args):形式参数列表,String[]是一种引用数据类型,args是一个局部变量的变量名
//所以,以下只有args这个局部变量名可以自定义
//主方法main只能这样编写,程序入口【SUN公司规定的】
public static void main(String[] args){
//这里是程序入口,一定会执行。
//main方法是JVM调用的,一个入口位置
//从这里作为起点,开始执行程序
//既然如此,我们可以在此编写java语句从而来调用其他方法
//调用MethodTest03的sum方法,传递两个实参。
MethodTest03.sum(10,20);//实际上,执行到这里,main方法暂停,执行sum方法,sum方法执行结束后,这行代码执行结束。继续执行main方法中代码
//【注意的是,方法体中代码是由上而下顺序依次执行,第118行代码不结束,
//第124行他就不会执行】
//一个方法可以被重复调用
int a=100;
MethodTest03.sum(a,500);//(a,500)实参列表
//再调用一次
int k=90;
int f=10;
MethodTest03.sum(k,f);//(k,f)实参列表
}
//自定义方法,不是程序入口
//方法功能:计算两个int类型数据的和,不要求返回结果,但要求将结果直接输出到控制台
//修饰符列表:public static
//返回值类型:void
//方法名:sum
//形参列表:(int x,int y)
//方法体:主要任务是求和后输出计算结果
public static void sum(int i,int j){
System.out.println(i+"+"+j+"="+(i+j));
}
}
方法的调用不一定在main方法中,可以在其他方法中,只要是程序可以执行到的位置,都可以调用其他方法
public class MethodTest04{
public static void sum(int a,int b){
System.out.println(a+"+"+b+"="+(a+b));
//调用doSome方法
MethodTest04.doSome();
}
//主方法
public static void main(String[] args){
//调用sum方法
MethodTest04.sum(1,2);
System.out.println("Hello World!");
}
public static void doSome(){
System.out.println("do some!");
}
}
方法调用时要求实参和形参个数对应相同,数据类型对应相同
类型不同时要求进行相应的自动类型转换
public class MethodTest05{
public static void main(String[] args){
//编译报错,参数数量不同
//MethodTest05.sum();
//编译报错,实参和形参类型不相同
//MethodTest05.sum(true,false);
//可以
MethodTest05.sum(10L,20L);
//存在自动类型转换,int转换long
MethodTest05.sum(10,20);
//编译报错,参数类型不是对应相同
//MethodTest05.sum(3.0,20);
//可以
MethodTest05.sum((long)3.0,20);
}
public static void sum(long a,long b){
System.out.println(a+"+"+b+"="+(a+b));
}
}
方法的调用:
1 方法的修饰符列表有static关键字的,完整的调用方式:类名.方法名(实参列表);
2 有的时候,可以省略不写“类名.”,在什么情况下可以省略?
m1(){
m2();
}
m1方法和m2方法在同一个类体当中,“类名.”可以省略不写
调用的方法和被调用的方法在同一个类体当中
3 建议在一个java源文件中只定义一个class,比较清晰,这里是为了说明的目的
在一个java源文件中定义多个class,不要模仿
public class MethodTest06{
public static void main(String[] args){
//完整调用
MethodTest06.m();
m();//编译通过
//调用其他类的方法【不是本类】
A.doOther();
//编译报错,省略“类名.”后,默认从MethodTest06,即当前类中找“doOther”方法,但是该方法不存在
//doOther();
}
public static void m(){
System.out.println("m方法被调用!");
//完整调用
MethodTest06.m2();
//省略的方式
m2();
A.m2();
}
public static void m2(){
System.out.println("m2方法被调用!");
}
}
class A{
public static void doOther(){
System.out.println("A的doOther方法被调用!");
}
public static void m2(){
System.out.println("A的m2方法被调用!");
}
}
对于当前程序来说:
- main方法最先被调用,main方法也是最后一个结束
- m3方法最后调用,m3方法也是最先结束
main方法结束后,整个程序结束【在现阶段来】
无需刻意记忆,
方法体中代码由上而下按顺序依次执行,上一行代码未执行结束,下一行代码永远不会执行
public class MethodTest07{
public static void main(String[] args){
System.out.println("main begin");
m1();
System.out.println("main over");
}
public static void m1(){
System.out.println("m1 begin");
m2();
System.out.println("m1 over");
}
public static void m2(){
System.out.println("m2 begin");
m3();
System.out.println("m2 over");
}
public static void m3(){
System.out.println("m3 begin");
System.out.println("m3 over");
}
}
输出结果:
main begin
m1 begin
m2 begin
m3 begin
m3 over
m2 over
m1 over
main over
方法返回值类型不是void的时候:
1.方法必须百分百保证执行“return 值;”语句来值的返回。没有即报错。
2.一个方法有返回值时,我们调用这个方法,方法返回了一个值,对于调用者来说,可以选择接收,也可以选择不接收但是大部分情况下时要接收的
public class MethodTest08{
public static void main(String[] args){
//调用方法
divide(10,3);
//【什么都没发生,因为这里并没有选择接收返回值,但是方法运行了】
//接收返回值
//利用变量接收
//变量数据类型必须和返回值类型保持一致,或者可以自动类型转换
//boolean b=divide(10,3);//编译报错,类型不兼容
//赋值运算符右边先执行,将执行结果赋值给左边的变量
int i=divide(10,3);
System.out.println(i);
long x=divide(10,3);
System.out.println(x);
System.out.println(divide(10,3));//也可以直接将返回值打印输出出来
}
//编译报错:缺少返回语句
/*
public static int divide(int a,int b){
}
*/
//编译报错:缺少返回值
/*
public static int divide(int a,int b){
return;
}
*/
//编译报错:方法定义的时候要求返回int类型,此时返回布尔类型,类型不兼容
/*
public static int divide(int a,int b){
return true;
}
*/
//可以,但是没有满足需求
/*
public static int divide(int a,int b){
return 1;
}
*/
/*
public static int divide(int a,int b){
int c=a/b;
return c;
}
*/
public static int divide(int a,int b){
return a/b;
}
}
深入探究return语句
-
return语句一旦执行,所在方法执行结束
-
在“同一个作用域”中,return语句下面不能编写任何代码,因为这些代码会永远执行不到,编译报错
public class MethodTest09{
public static void main(String[] args){
/*
int retValue=m();
System.out.println(retValue);
*/
//编译错误,调用m方法并没有传递实参,即没有括号,编译器会认为这个m是某个变量。
//System.out.println(m);
//编译通过,正确地调用m方法。即使形参没有,但是(形参)这个格式一定要有。
System.out.println(m());
}
//编译报错,缺少返回语句,编译器认为 return 1;这条语句并不能完全保证执行到。
/*
public static int m(){
int a=10;
if(a>3){
return 1;
}
}
*/
//编译通过,带有else的控制语句一定会保证有一个分支执行,return 1; 或者 return 0;这两个肯定会执行一个
/*
public static int m(){
int a=10;
if(a>3){
return 1;
}else{
return 0;
}
}
*/
//在这里,需要说明的是下面的代码和上面的完全一样。
//首先if语句里a>3可能为真也可能为假
//真-有return 1执行,整个方法执行结束
//假-有return 0执行,整个方法执行结束
//不管怎么样,都会有 return 值 语句执行
/*
public static int m(){
int a=10;
if(a>3){
return 1;
}
return 0;
}
*/
/*
public static int m(){
int a=10;
if(a>3){
return 1;
//System.out.println("Hello World!");//此行代码永远执行不到,无法访问的语句,编译报错
}
System.out.println("Hello World!");//现在你应该明白在同一个作用域中return语句下面不能加java语句了吧
return 0;
}
*/
//另外,还可以使用三元运算符达到最简代码的目的
public static int m(){
return 10>3?1:0;//后面的10>3?1:0是三元运算符,真输出1,假输出0
}
}
在返回值类型为void的情况下使用 return;语句
return;语句出现在返回值类型为void的方法中是为了结束当前方法
public class MethodTest10{
public static void main(String[] args){
m();
//return 10;不能这样写,这里是main方法,main方法返回值类型是void类型,只能写return;
//当然写了return;语句后,下面也不能写代码了,因为访问不到。
for(int i=10;i>0;i--){
if(i==2){
return;
}
System.out.println("i的值-->"+i);
}
System.out.println("Hello Word!");
//retrun;直接终止了整个main方法的运行,所以Hello World!并没有输出
//小结一下,main方法它还是方法,不要将他特殊化,return语句肯定能在main方法里使用
}
//编译报错,对返回值类型为void的方法不能使用 return 值; 这样的语句
/*
public static void m(){
return 10;
}
*/
public static void m(){
for(int i=0;i<10;i++){
if(i==5){
return;//直接终止整个m方法,Hello World执行不到
//break;//终止当前for循环
}
System.out.println("i -->"+i);
}
System.out.println("Hello World!");
}
}
方法在执行过程中,在JVM中的内存是如何分配的,内存是如何变化的
1.方法只定义,不调用不会执行,并且在JVM中也不会给方法分配“运行所属”的内存空间。
只有在调用这个方法的时候,才会动态的给这个方法分配所属的内存空间
2.在JVM内存划分上有这样三块主要的内存空间(当然除了这三块主要的还有其他内存空间)
- 方法区内存
- 堆内存
- 栈内存
3.关于“栈”数据结构
- 栈:stack,一种数据结构
- 数据结构反应的是数据的存储形态
- 数据结构是独立的学科,不属于任何编程语言范畴,只不过在大多数语言当中要使用数据结构
- 作为程序员要提前精通:数据结构和算法【计算机专业必修】
- java程序员不精通数据结构和算法也能进行java开发,因为java语言拥有一套庞大的类库支撑
别人写好,直接使用即可【javase当中的集合章节使用了大量数据结构】 - 常见的数据结构:
-数组
-队列
-栈
-链表
-二叉树
-哈希表/散列表
…
4.方法代码片段存在哪里?方法执行的时候执行过程的内存在哪里分配?
-
方法代码片段属于.class字节码文件的一部分,字节码文件在类加载的时候,
将其放到了方法区当中。所以JVM中的三块主要内存空间中方法去内存最先有
数据。存放了代码片段 -
代码片段虽然在方法区内存中只有一份,但是可以被重复调用。
每一次调用这个方法的时候,需要给该方法分配独立活动场所,在
栈内存中分配。【栈内存中分配方法运行的所属内存空间】
5.方法在调用的瞬间,会给该方法分配内存空间,会在栈中发生压栈动作,方法执行结束后,给该方法分配的内存全部释放,此时发生弹栈动作。
- 压栈:给方法分配内存
- 弹栈:释放该方法的内存空间
6.局部变量在“方法体”内声明,局部变量运行阶段内存在栈中分配。
内存分析练习
注意:在 Editplus中,字体为红色的表示一个类的名字,并且这个类是JavaSE类库中自带的
我们自定义的MethodTest01类名是黑色显示的
JavaSE类库中自带的类,例如:String.class、System.class,这些类的名字也是标识符
只要是类名,就一定是标识符
重点:方法调用的时候,在参数传递的时候,实际上传递的是变量保存的那个“值”传过去了
public class MethodTest01{
public static void main(String[] args){
int a=10;
int b=20;
int retValue=sumInt(a,b);
System.out.println("retValue = "+retValue);
}
public static int sumInt(int i,int j){
int result=i+j;
int num=3;
int retValue=divide(result,num);
return retValue;
}
public static int divide(int x,int y){
int z=x/y;
return z;
}
}
画出这个程序执行过程的内存分析图
画图依据:
1.只要涉及到参数传递的问题,传递的是变量保存的值
2.画图的时候,必须遵循“方法自上而下的顺序依次执行”这个原则
public class MethodTest02{
public static void main(String[] args){
int i=10;
method(i);
System.out.println("main -->"+i);
}
public static void method(int i){
i++;
System.out.println("method -->"+i);
}
}
画图分析
程序每走一步,画一步即可,注意变量是先右后左
方法重载机制
- 以下程序先不使用方法重载机制,分析程序的缺点???
- 以下程序没有语法错误,运行也是正常的,你就分析以下代码风格存在什么缺点 !
public class OverloadTest01{
//主方法
public static void main(String[] args){
int x = sumInt(10, 20);
System.out.println(x);
long y = sumLong(10L, 20L);
System.out.println(y);
double z = sumDouble(10.0, 20.0);
System.out.println(z);
}
// 定义一个计算int类型数据的求和方法
public static int sumInt(int a, int b){
return a + b;
}
// 定义一个计算long类型数据的求和方法
public static long sumLong(long a, long b){
return a + b;
}
// 定义一个计算double类型数据的求和方法
public static double sumDouble(double a, double b){
return a + b;
}
}
sumInt、sumLong、sumDouble不是功能“相同”,是功能“相似”。
三个方法功能不同,但是相似,分别起了三个不同的名字,有什么缺点??
缺点包括两个:
- 第一个:代码不美观(不好看、不整齐)。【这是次要的】
- 第二个:程序员需要记忆更多的方法名称,程序员比较累。
使用方法重载机制,解决之前的两个缺点。
- 优点1:代码整齐美观。
- 优点2:“功能相似”的,可以让“方法名相同”,更易于以后的代码编写。
在Java语言中,是怎么进行方法区分的呢?
- 首先java编译器会通过方法名进行区分。
- 但是在java语言中允许方法名相同的情况出现。
- 如果方法名相同的情况下,编译器会通过方法的参数类型进行方法的区分。
public class OverloadTest02{
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));
}
// 定义一个计算int类型数据的求和方法
public static int sum(int a, int b){
System.out.println("int求和");
return a + b;
}
// 定义一个计算long类型数据的求和方法
public static long sum(long a, long b){
System.out.println("long求和");
return a + b;
}
// 定义一个计算double类型数据的求和方法
public static double sum(double a, double b){
System.out.println("double求和");
return a + b;
}
}
方法重载(overload)
什么时候需要考虑使用方法重载??
在同一个类当中,如果“功能1”和“功能2”它们的功能是相似的,那么可以考虑将它们的方法名一致,这样代码既美观,有便于后期的代码编写(容易记忆,方便使用)。
【注意】:方法重载overload不能随便使用,如果两个功能压根不相干不相似,根本没关系,此时两个方法重载机制的话,会导致编码更麻烦,无法进行方法功能的区分。
什么时候代码会发生方法重载??
时候代码会发生方法重载?
条件1:在同一个类当中
条件2:方法名相同
条件3:参数列表不同
参数的个数不同算不同
参数的类型不同算不同
参数的顺序不同算不同
只要同时满足以上3个条件,那么我们可以认定方法和方法之间发生了
重载机制。
注意:
不管代码怎么写,最终一定能让java编译器很好的区分开这两个方法。
方法重载和方法的“返回值类型”无关。
方法重载和方法的“修饰符列表”无关。
public class OverloadTest03{
public static void main(String[] args){
m1();
m1(100);
m2(10, 3.14);
m2(3.14, 10);
m3(100);
m3(3.14);
}
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("m2(int x, double y)");
}
// 参数的顺序不同,也算不同。
public static void m2(double y, int x){
System.out.println("m2(double y, int x)");
}
public static void m3(int x){
System.out.println("m3(int x)");
}
// 参数的类型不同。
public static void m3(double d){
System.out.println("m3(double d)");
}
//分析:以下两个方法有没有发生重载?
// 编译器报错了,不是重载,这是重复了:呵呵。
/*
public static void m4(int a, int b){
}
public static void m4(int x, int y){
}
*/
// 这两个方法有没有发生重载呢?
// 这不是重载,这是方法重复了。
/*
public static int m5(){
return 1;
}
public static double m5(){
return 1.0;
}
*/
//这两个方法重载了吗?
// 这个方法没有修饰符列表
// 这不是重载,是重复了。
/*
void m6(){
}
// 这个有修饰符列表
public static void m6(){
}
*/
}
class MyClass{
// 不在同一个类当中,不能叫做方法重载。
public static void m1(int x, int y){
}
}
通过源代码查看发现println()方法重载了
public class OverloadTest04{
public static void main(String[] args){
// 大家是否承认:println是一个方法名。
// println我承认是方法名了,但是这个方法谁写的?SUN公司的java团队写的。
// 你直接用就行。
// println()方法肯定是重载了。(不信,你可以翻阅一下SUN公司写的源代码看看。)
// 对于println()方法来说,我们只需要记忆这一个方法名就行。
// 参数类型可以随便传。这说明println()方法重载了。
System.out.println(10);
System.out.println(3.14);
System.out.println(true);
System.out.println('a');
System.out.println("abc");
System.out.println(100L);
System.out.println(3.0F);
// 调用m方法
m(100);
}
public static void m(int i){
}
}
方法的递归
1、什么是方法递归?
方法自己调用自己,这就是方法递归。
2、当递归时程序没有结束条件,一定会发生:
栈内存溢出错误:StackOverflowError
所以:递归必须要有结束条件。(这是一个非常重要的知识点。)
JVM发生错误之后只有一个结果,就是退出JVM。
3、递归假设是有结束条件的,就一定不会发生栈内存溢出错误吗?
假设这个结束条件是对的,是合法的,递归有的时候也会出现栈内存溢出错误。
因为有可能递归的太深,栈内存不够了。因为一直在压栈。
4、在实际的开发中,不建议轻易的选择递归,能用for循环while循环代替的,尽量
使用循环来做。因为循环的效率高,耗费的内存少。递归耗费的内存比较大,另外
递归的使用不当,会导致JVM死掉。
(但在极少数的情况下,不用递归,这个程序没法实现。)
所以:递归我们还是要认真学习的。
5、在实际的开发中,假设有一天你真正的遇到了:StackOverflowError
你怎么解决这个问题,可以谈一下你的思路吗?
我来谈一下我的个人思路:
首先第一步:
先检查递归的结束条件对不对。如果递归结束条件不对,
必须对条件进一步修改,直到正确为止。
第二步:假设递归条件没问题,怎么办?
这个时候需要手动的调整JVM的栈内存初始化大小。
可以将栈内存的空间调大点。(可以调整大一些。)
第三步:调整了大小,如果运行时还是出现这个错误,
没办法,只能继续扩大栈的内存大小。
(java -X)这个可以查看调整堆栈大小的参数
递归原理
public class RecursionTest01{
// 入口
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()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
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()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
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()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
public static void doSome(){
System.out.println("doSome begin");
// 调用方法:doSome()既然是一个方法,那么doSome方法可以调用吗?当然可以。
doSome();
// 这行代码永远执行不到。
System.out.println("doSome over");
}
public static void doSome(){
// 假设突然有一天,一个条件成立了,这个doSome结束了
if(某个条件成立了){
return;
}
}
*/
}
递归没有结束条件的时候会发生栈内存溢出错误
// 先不使用递归,请编写程序,计算1~n的和。
public class RecursionTest02{
public static void main(String[] args){
// 1~10的和
int retValue1 = sum(10);
System.out.println(retValue1);
// 1~3的和
int retValue2 = sum(3);
System.out.println(retValue2); // 6 (1 + 2 + 3)
}
// 单独编写一个计算1~n和的方法
public static int sum(int n){
int result = 0;
for(int i = 1; i <= n; i++){
result += i;
}
return result;
}
}
// 使用递归,请编写程序,计算1~n的和。
public class RecursionTest03{
public static void main(String[] args){
// 1~3的和
int n = 3;
int r = sum(n);
System.out.println(r); // 6
}
// 大家努力的去看,去听,自己写不出来没关系,关键是能不能看懂。
// 单独编写一个计算1~n和的方法
// 这个代码修改为递归的方式。
// 3 + 2 + 1
public static int sum(int n){
//n最初等于3
// 3 + 2 (2是怎么的出来的:n - 1)
//sum(n - 1);
if(n == 1){
return 1;
}
// 程序能执行到此处说明n不是1
return n + sum(n-1);
}
}
// 使用递归的方式计算N的阶乘
// 5的阶乘:5 * 4 * 3 * 2 * 1
// 用递归的方式实现一个。
// 使用for循环的方式实现一个。
public class RecursionTest04{
public static void main(String[] args){
int n = 5;
int jieGuo = jieCheng(n);
System.out.println(jieGuo); // 120
System.out.println(jieCheng2(5));
}
public static int jieCheng2(int n){
int result = 1;
for(int i = 2; i <= n; i++){
result *= i;
}
return result;
}
public static int jieCheng(int n){
// 5 * 4 * 3 * 2 * 1
if(n == 1){
return 1;
}
/*
int result = n * jieCheng(n - 1);
return result;
*/
return n * jieCheng(n - 1);
}
}
下一篇:面向对象详解