• 【JAVASE系列】03_方法(定义,重载,递归)


    一、方法

    • 方法的本质:一段独立的代码片段,并且这段代码片段可以完成某个特定的功能,并且可以被重复的使用。

    • 方法定义在类体当中,在一个类当中可以定义多个方法,方法编写的位置没有先后顺序,可以随意。

    • 方法体当中不能再定义方法。

    • 方法体由java语句构成,方法体当中的代码遵守自上而下的顺序依次执行。

    定义一个方法完成计算两个int类型的数据并输出:

    public class Day1 {
        public static void main(String[] args) {
            Day1.sumInt(10,20);
        }
    
        public static void sumInt(int a,int b) {
            int c=a+b;
            System.out.println(a+" + "+b+" = " +c);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1、方法的定义

    【1】方法怎么定义,语法结构:

    [修饰符列表] 返回值类型 方法名(形式参数列表){
    		方法体;
    }
    
    • 1
    • 2
    • 3

    【2】对上面语法的解释:

    • 关于修饰符列表:可选性,不是必须的。可写成public static

    当方法的修饰符列表当中有static关键字的话,怎么调用这个方法?

    类名.方法名(实际参数列表);
    
    • 1
    • 返回值:

      • 一个方法是可以完成某个特定的功能的,这个功能结束之后大多数都是需要返回最终执行结果的,最终返回的执行结果可能是一个具体的数据,而只要是数据就一定会有类型。而这个具体存在的数据就是返回值。
    • 返回值类型:

      • 可以是byte,short,String,void,等等

      • 返回值类型可以是任意一种java的类型,包括基本数据类型和所有的引用数据类型。

      • 如果一个方法在执行结束之后不返回任何数据的话,返回值类型的位置必须写成void关键字。

      • 返回值类型如果不是void,表示这个方法执行结束之后必须返回一个具体的数值,如果此时没有返回数值的话 就会报错。

      • 如果返回值的类型是void的时候,在方法体当中不能编写return 值,但是可以编写return;这样的语句。

      • 只要带有return关键字的语句执行,那么return语句所在的方法就结束了。【不是JVM结束,是return所在的方法结束了】

    • 方法名:

      • 方法名只要是合法的标识符就行
      • 方法名最好见名知意
      • 最好是动词
      • 方法名首字母要求小写,后面每个单词首字母大写
    • 形式参数列表:

      • 形参是局部变量:int a,double b,float c…
      • 形参的个数是:0-N个
      • 多个形参之间使用逗号分隔
      • 形参当中其决定性作用的是形参的数据类型,形参的名字就是局部变量的名字
      • 实参列表和形参列表必须满足:数量相同,类型也对应相同
        public static void a(){
            
        }
    
    • 1
    • 2
    • 3

    2、方法的调用

    方法只定义不去调用是不会执行的,只有在调用的时候才会执行

    类名.方法名(实参列表);
    
    • 1

    上面是一条java语句,表示调用某个类的某个方法,传递这样的实参。

    //public表示公开的
    //class表示定义类
    //Day1表示类名
    public class Day1 {//表示定义一个公开的类,名字叫做Day1
        //由于是公开的类,因此源文件必须起名也是Day1
    
        //类体:
        //类体中不能直接编写java语句,除了声明变量之外
        //方法出现在类体当中
    
        //方法:
        //public表示公开的,static表示静态的,void表示方法执行结束之后不返回任何数据,main表示主方法
        //(String[] args):形式参数列表,其中的String[]是一种引用数据类型,args是一个局部变量的变量名
        //所以以下只有args这个局部变量的变量名是随便取的
        //主方法就需要这样固定编写,这是程序的入口
        public static void main(String[] args) {
            
            //调用sumInt方法,传递两个实参
            Day1.sumInt(10,20);
            
            //一个方法可以被重复使用,重复调用
            int a=100;
            Day1.sumInt(a,30);
        }
    /*
    * 自定义一个方法,不是程序的入口
    * 方法的作用:计算两个int类型数据的和,不要求返回结果,但是要求将结果直接输出在控制台
    * 修饰符列表:public static
    * 返回值类型:void
    * 方法名:sumInt
    * 形式参数列表:(int x,int y)
    * 方法体:主要任务是求和之后输出计算结果
    * */
        public static void sumInt(int a,int b) {
            int c = a + b;
            System.out.println(a + " + " + b + " = " + c);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    在非主函数当中调用方法:

    public class Method {
        
        public static void sum(int a,int b){
            System.out.println(a+" = "+b+" = "+(a+b));        
            //调用doSome方法
            Method.doSome();
        }
        
        //主方法
        public static void main(String[] args) {        
            //调用sum方法
            Method.sum(1,2);
        }
        
        public static void doSome(){
            System.out.println("doSome!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    调用方法时,方法名后面必须带有括号:

    不然编译器会认为方法名是一个变量

    public class Method1 {
        public static void main(String[] args) {
            System.out.println(m());//直接调用方法
        }
        public static int m(){
            int a=10;
            if(a>3){
                return 1;
            }else{
                return 0;
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    3、实参与形参

    方法调用中实参与形参的问题:

    • 方法调用的时候实参和形参要求个数对应相同,数据类型对应相同
    • 类型不同的时候要求能够进行相应的类型转换
    public class Method {
    
        public static void sum(long a,long b){
            System.out.println(a+" = "+b+" = "+(a+b));
    
            //调用doSome方法
            Method.doSome();
        }
    
        //主方法
        public static void main(String[] args) {
    
            //编译错误:实参和形参的类型不是对应相同的
            //Method.sum(true,false);
            
            //可以,自动类型转换
            Method.sum(10,20);
            
            //可以
            Method.sum(10L,30L);
            
            //编译错误:参数类型不是对应相同的
            Method.sum((long)3.0,20);
        }
        public static void doSome(){
            System.out.println("doSome!");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    方法的修饰符列表当中有static关键字

    4、方法中有static

    • 1、方法的修饰符列表当中有static关键字,则完整的调用方法是:类名.方法名(实参列表)
    • 2、可以省略的情况:调用的方法必须是在本类当中

    方法的返回值不是void的时候:

    • 要求方法必须保证执行 return 值 这样的语句来完成值的返回,没有这个语句,则编译器会报错
    • 当方法有返回值的时候,调用者可以选择不去接受这个返回值

    5、return返回值

    • 带有return关键字的java语句只要执行,所在的方法执行结束
    • 在同一个作用域当中,return语句下面不能编写任何代码,因为这些代码永远都执行不到,所以编译报错
    • 对于结果类型为空,无法返回值

    以下代码编译报错:

        //编译报错,因为缺少返回语句,以下程序编译器认为无法百分百保证return语句会执行
        public static int m(){
            int a=10;
            if(a>3){
                return 1;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    以下代码编译通过:

        //编译通过,因为可以保证return语句会执行
        public static int m(){
            int a=10;
            if(a>3){
                return 1;
            }else{
                return 0;
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    二、方法的内存分配

    方法在执行过程当中,内存是如何分配的?

    1、方法只定义,不调用,是不会执行的,并且JVM中也不会给该方法分配“运行所属”的内存空间。只有调用方法的时候,才会分配内存空间

    2、在JVM内存划分上有三块主要的内存空间:

    • 方法区内存
    • 堆内存
    • 栈内存

    3、方法代码片段存在哪里?

    • 方法代码片段属于.class字节码文件的一部分,字节码文件在类加载的时候,将其放到了方法区当中,所以JVM中的三块主要的内存空间中方法区内存最先有数据,存放了代码片段。
    • 代码片段虽然在方法区内存当中只有一份,但是可以被重复调用。
    • 每一次调用这个方法的时候,需要给该方法分配独立的活动场所,在栈内存当中分配。【栈内存当中分配方法运行的所属内存空间】

    4、方法调用的时候,会给该方法分配独立的内存空间,在栈中分配。此时发生压栈动作,方法执行结束之后,给该方法分配的内存空间全部释放,此时发生出栈动作。

    • 压栈:给方法分配内存
    • 出栈:释放该方法的内存空间

    三、方法的重载机制

    方法重载机制:overload

    1、方法重载的优点

    • 程序员调用方法的时候,比较方便
    • 代码美观

    2、什么时候考虑使用方法重载?

    • 功能相似的时候,尽可能让方法名相同,【功能不同的时候,方法名尽量不同】

    3、什么条件满足之后构成了方法重载?

    • 在同一个类当中
    • 方法名相同
    • 参数列表不同:
      • 数量不同
      • 顺序不同
      • 类型不同
    public class Overload2 {
        //以下两个方法构成了重载:数量不同
        public static void m1(){}
        public static void m1(int a){}
        
        //以下两个方法构成了重载:顺序不同
        public static void m2(int a,double b){}
        public static void m2(double a,int b){}
        
        //以下两个方法构成了重载:类型不同
        public static void m2(int a){}
        public static void m2(double a){}
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    4、方法重载和什么有关系?

    • 方法重载和方法名+参数列表有关系
    • 方法重载和返回值类型无关
        //编译错误:以下不是方法重载,而是发生了方法重复(与形参名无关)
        public static void m3(int a){}
        public static void m3(int b){}
        
        //编译错误:以下不是方法重载,而是发生了方法重复(与返回值类型无关)
        public static void m3(int a){}
        public static int m3(int a){}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    四、方法的递归调用

    1、什么是递归

    递归即方法调用自身

    2、递归很耗费栈内存,递归算法能不使用的时候,尽量不使用

    3、栈溢出:

    public static void main(String[] args) {
            System.out.println("main begin");
            //调用doSome方法
            doSome();
            System.out.println("main over");
        }
    
        //以下代码片段虽然只有一份,但是可以被重复调用
        //并且只要调用doSome方法,就会在栈内存当中重新分配一块所属的内存空间
        public static void doSome(){
            System.out.println("doSome begin");
            doSome();
            System.out.println("doSome over");
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    以上程序发生了这样一个错误【不是异常,是错误Error】

    java.lang.StackOverflowError
    
    • 1
    • 栈内存溢出错误
    • 错误无法挽回,只有一个结果,即JVM停止工作

    4、递归必须有结束条件,没有结束条件一定会发生栈内存溢出错误

    使用递归计算1-N的求和:

    /*
    * 使用递归计算1-N的求和:
    *   4+3+2+1:N的初值为4,建议采用这种方式
    * */
    public class Recursion2 {
        public static void main(String[] args) {
            int n=4;
            int retValue=sum(n);
            System.out.println(retValue);
        }
    
        public static int sum(int n) {
            if(n==1){
                return 1;
            }
            return n+sum(n-1);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
  • 相关阅读:
    Linux 权限系统
    【Linux】从零开始学习Linux基本指令(三)
    RF电路设计常见bug及解决方法
    MySQL源码解析之执行计划
    12. 机器学习 - 拟合
    SpringBootApplication注解
    MongoDB快速上手
    ESP32系列--第九篇 ADC的使用
    微服务架构 | 超时管理
    基于信息检索和深度学习结合的单元测试用例断言自动生成
  • 原文地址:https://blog.csdn.net/wxfighting/article/details/125473124