Java方法

1.什么是方法

方法,在很多语言中被称为函数。在java中称为方法,它代表着一个独立的,可复用的,功能。

如:

Math.random() 这句代码就是在调用一个现成的方法,它的功能是返回一个随机产生的[0,1)的double值。
              Math类的random()方法                                		
System.out.println() 这句代码也是在调用一个现成的方法,它的功能是输出()中的内容,并换行。
    		PrintStream类 println()方法,这里的System.out是一个PrintStream类的对象
Scanner input = new Scanner(System.in);

int num = input.nextInt();  这句代码的 nextInt()也是一个方法,它的功能是从控制台接收一个int值

2.为什么要定义方法

当我们需要重复使用一段代码的时候,我们通常将这段代码封装为一个方法。

3.如何定义方法

一个完整的方法必须有五部分

修饰符 返回值类型 方法名(形参列表){
        方法体
}

方法体语句:实现方法功能的语句,可以是1~n条语句组成。

修饰符:对方法的使用范围进行规定。

方法名:就是一个标识符而已,需要见名知意,遵循小驼峰命名法(即从第2个单词开始,首字母大写),代表方法的功能。

返回值类型,有两种情况:

  • void:代表这个方法运行完之后,没有结果返回。方法体语句中没有 “return 结果; ”的语句

  • 非void:可以是int,double,String, int[]等各种Java的类型,代表这个方法运行完之后,必须给调用者返回一个结果。方法体语句中必须由“ return 结果;” 的语句

形参列表

  • ():无参或空参

  • (数据类型 参数名) 或(数据类型 参数名1, 数据类型 参数名2) 或更多个参数:有参


    //无参
    public static void test1() {
        System.out.println("哈哈哈哈");
    }

    //有参
    public static void test2(int a, int b) {
        System.out.println(a < b ? b + "大" : a + "大");
    }

4.如何调用定义好的方法

4.1 跨类调用

类名.方法名(【实参列表】); //没有接收返回值

变量 = 类名.方法名(【实参列表】);//用变量接收方法的返回值

实参列表必须与被调用方法的形参列表一一对应。即实参的个数、类型、顺序必须与形参一一对应。

如果被调用方法的返回值类型是void,那么就不需要接收。

如果被调用方法的返回值类型不是void,是int,int[],double等其他类型,就可以用变量接收返回值。接收返回值的变量类型也要合适。

public class Test {
    public static void main(String[] args) {
        Tools.test1(4,8);
    }



}

4.2 本类调用

方法名(【实参列表】); //没有接收返回值

变量 = 方法名(【实参列表】);//用变量接收方法的返回值

实参列表必须与被调用方法的形参列表一一对应。即实参的个数、类型、顺序必须与形参一一对应。

如果被调用方法的返回值类型是void,那么就不需要接收。

如果被调用方法的返回值类型不是void,是int,int[],double等其他类型,就可以用变量接收返回值。接收返回值的变量类型也要合适。

public class Test {
    public static void main(String[] args) {
        //调用Tools中的方法
      test1(4,8);
    }
    public static void test1(int a, int b) {
        System.out.println(a < b ? b + "大" : a + "大");
    }


}

4.3 方法小结

  • 方法不调用不执行

  • 方法调用1次执行1次

5.方法内存分析

简单分析:

6.方法的参数传递机制

6.1 谁给谁传值?

实参给形参传值

6.2 传什么值?

  • 基本数据类型:实参给形参的是数据值,或者数据值的副本

  • 引用数据类型:实参给形参的是地址值,或者地址值的副本

6.3 形参的修改反过来会影响实参吗?

(1)基本数据类型

参数是基本数据类型时,形参的修改与实参完全无关。

(2)引用数据类型

参数是引用数据类型时,形参数组修改了元素,相当于实参数组修改了元素

除了8种基本数据类型以外的,都是引用数据类型,包括数组、类等。

(3)如何让基本数据类型的实参得到形参修改后的值?

(4)引用数据类型的形参所有修改都影响实参吗?

不是。当形参换新地址值时,就与实参无关。

(5)如何得到新数组?

案例:

public static void swap(int a,int b){
    int temp = a;
    a = b;
    b = temp;
}

public static void main(String[] args){
    int x = 1;
    int y = 2;
    System.out.println("x="+x + ",y=" + y);//x=1,y=2
    swap(x,y);
    System.out.println("x="+x + ",y=" + y);//x=1,y=2
    //因为a,b是基本数据类型的形参。修改它又没有返回,与实参无关,所以实参不变。
}

public static void reverse(int[] arr){
    for(int left=0,right=arr.length-1; left<right; left++,right--){
        int temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
    }
}

public static void main(String[] args){
    int[] nums = {1,2,3};
    for(int i=0; i<nums.length; i++){
        System.out.print(nums[i] + " ");
    }
    System.out.println();
    //1 2 3
    
    
    reverse(nums);
    
    System.out.println("调用reverse之后:")
    for(int i=0; i<nums.length; i++){
        System.out.print(nums[i] + " ");
    }
    System.out.println();
    //3 2 1
    //因为arr是数组类型,即引用数据类型,nums实参给arr形参的是数组的首地址,在reverse方法中没有产生新数组对象,
    //直接针对旧数组修改了,那么相当于实参与形参是同一个数组。
}

 7.可变参数

7.1 如何定义

【修饰符】 返回值类型 方法名(数据类型... 参数名){
    
}

可变参数的形参:它可以当做数组使用。

可变参数对于的实参,可以是:

  • 对应类型的数组

  • 0~n个的元素

public class TestVarParam {
    //需求:定义一个方法,可以求任意个整数的和
    public static int sum(int[] nums){
        int result = 0;
        for (int i = 0; i < nums.length; i++) {
            result += nums[i];
        }
        return result;
    }

    public static void main(String[] args) {
        //求1,2,3的和
        int[] arr1 =  {1,2,3};
        int sum1 = sum(arr1);
        System.out.println("sum1 = " + sum1);

        //求1,2,3,4,5
        int[] arr2 =  {1,2,3,4,5};
        int sum2 = sum(arr2);
        System.out.println("sum2 = " + sum2);

        //求1,2,3,4,5,6,7,8,9,10
      //  int sum3 = sum(1,2,3,4,5,6,7,8,9,10);//报错
     //   System.out.println("sum3 = " + sum3);
    }
}
public class TestVarParam2 {
    //需求:定义一个方法,可以求任意个整数的和
    //在sum方法中,可变参数nums直接当成数组使用即可。
    public static int sum(int... nums){
//        System.out.println(nums.length);
        int result = 0;
        for (int i = 0; i < nums.length; i++) {
            result += nums[i];
        }
        return result;
    }

    public static void main(String[] args) {
        //求1,2,3的和
        int[] arr1 =  {1,2,3};
        int sum1 = sum(arr1);
        //实参arr1是数组类型,可以被可变参数nums赋值
        System.out.println("sum1 = " + sum1);

        //求1,2,3,4,5
        int[] arr2 =  {1,2,3,4,5};
        int sum2 = sum(arr2);
        //实参arr2是数组类型,可以被可变参数nums赋值
        System.out.println("sum2 = " + sum2);

        //求1,2,3,4,5,6,7,8,9,10
        int sum3 = sum(1,2,3,4,5,6,7,8,9,10);
        //10个元素直接 给可变参数nums赋值
        System.out.println("sum3 = " + sum3);

        int sum4 = sum();
        //0个元素直接 给可变参数nums赋值
        //等价于
        //int[] arr4 = new int[0];//长度为0的数组
        // int sum4 = sum(arr4);
        System.out.println("sum4 = " + sum4);
    }
}

7.2  可变参数 VS 数组

 所有数组类型的形参都可以换成可变参数吗?

不是

数组类型的形参可变参数的形参
位置没有限制必须是最后一个形参
个数没有限制只能有1个
实参必须是对应类型的数组(1)可以是对应类型的实参(2)也可以是0~n个元素

总结:

  • 可变参数不能完全取代数组

  • 能使用可变参数的地方,可变参数比数组类型灵活

public class TestVarParam3 {
    public static void swap1( int i, int j,int[] arr){
        //....
    }

    public static void swap2(int i, int j,int... arr){
        //....
    }

    public static void copy1(int[] arr1 , int[] arr2){
        //....
    }

    public static void copy2(int[] arr1 , int... arr2){
        //....
    }
}

8.方法的重载

方法的重载(Overload):是指在同一个类中,定义了两个或更多个方法名相同形参列表不同的方法,这些方法的关系就是重载关系。这里的形参列表不同是指形参的类型,或个数、或顺序不同。方法的重载与返回值类型、形参名、修饰符等无关。

方法重载调用的原则:

  • 先找实参的类型、个数、顺序与形参的类型、个数、顺序完全匹配的,找到就执行它。

  • 如果没有最匹配的,就找形参的类型>实参的类型,即形参的类型可以兼容实参的类型,找到就执行它。

  • 如果没有找到最匹配的,也没有找到可以兼容的,或者找到多个兼容程度相同的,都会报错。

public class TestOverload {
    //定义一个方法,可以返回两个整数的最大值
    public static int max(int a, int b){
        return a > b ? a : b;
    }

    //定义一个方法,可以返回两个小数的最大值
    public static double max(double a, double b){
        return a > b ? a : b;
    }

    //定义一个方法,可以返回三个整数的最大值
    public static int max(int a, int b,int c){
        int bigger = a > b ? a : b;
        return bigger > c ? bigger : c;
    }

    //定义一个方法,可以求任意个整数的最大值
    public static int max(int... nums){
        int biggest = nums[0];
        for (int i=1; i<nums.length; i++){
            if(nums[i] > biggest){
                biggest = nums[i];
            }
        }
        return biggest;
    }

    //定义一个方法,可以求任意个整数的最大值,至少传入1个整数
    public static int max(int first, int... nums){
        int biggest = first;
        for (int i=0; i<nums.length; i++){
            if(nums[i] > biggest){
                biggest = nums[i];
            }
        }
        return biggest;
    }

    public static void main(String[] args) {
        int result1 = max(5, 6);
        System.out.println("result1 = " + result1);

        double result2 = max(5.0, 6.0);
        System.out.println("result2 = " + result2);

        double result3 = max(5, 6.0);
        System.out.println("result3 = " + result3);

//        double result4 = max(5.0, 6.0, 4.0);//报错,无法找到最匹配的,也无法找到可以兼容的
//        System.out.println("result4 = " + result4);

        int result5 = max(5, 6,4);
        System.out.println("result5 = " + result5);

       // int result6 = max(5, 6,4,8);//报错,因为与max(int... nums)和max(int first, int... nums)都同样兼容
       // System.out.println("result6 = " + result6);

    }

    //理论上来说,可以是形参的顺序不同的两个方法构成重载
    /*public static int max(char a, int b){
        return a > b ? a : b;
    }
    public static int max(int a, char b){
        return a > b ? a : b;
    }*/
}

9.简单的递归使用

递归的难在于找到数学规律,数学公式。

什么是递归?递归是指一个方法自己调用自己。

案例1:求n!

    /*求n!
        1=1
        2=1*2
        3=1*2 *3
        4=1*2*3 *4
        f(1)=1
        f(2)=f(1)*2
        f(3)=f(2)*3
        f(4)=f(3)*4
     */
    public static int fun(int n){
        if (n<=1){
            return 1;
        }
        return n*fun(n-1);
    }

案例2:猴子吃桃

猴子吃桃子问题,猴子第一天摘下若干个桃子,当即吃了所有桃子的一半,还不过瘾,又多吃了一个。第二天又将仅剩下的桃子吃掉了一半,又多吃了一个。以后每天都吃了前一天剩下的一半多一个。到第十天,只剩下一个桃子。试求第一天共摘了多少桃子?

   /*
    猴子吃桃子问题,猴子第一天摘下若干个桃子,当即吃了所有桃子的一半,还不过瘾,又多吃了一个。
    第二天又将仅剩下的桃子吃掉了一半,又多吃了一个。以后每天都吃了前一天剩下的一半多一个。
    到第十天,只剩下一个桃子。试求第一天共摘了多少桃子?
    f(10) = 1
    f(9) = (1+1)*2=(f(10)+1)*2
    f(1) = n
    f(2) =n-( n/2)-1=n/2-1
    f(n)=(f(n+1)+1)*2
     */
    public static int eat(int n){
        if (n>10){
           return  0;
        }
        if (n==10){
            return 1;
        }
        return (eat(n+1)+1)*2;
    }

案例3:走台阶

有n级台阶,一次只能上1步或2步,共有多少种走法?

    /*
    有n级台阶,一次只能上1步或2步,共有多少种走法?
     1级     1                                       f(1)=1
     2级     11      2                               f(2)=2
     3级     111     12      21                      f(3)=3=f(2)+f(1)
     4级     1111    121     211     112  221        f(4)=4=f(3)+f(2)
                                                     f(n)=f(n-1)+f(n-2)
     */
    public static int move(int n){
        if (n<=2){
            return n;
        }
        return move(n-1)+move(n-2);
    }

案例4:不死神兔

用递归实现不死神兔:故事得从西元1202年说起,话说有一位意大利青年,名叫斐波那契。
在他的一部著作中提出了一个有趣的问题:假设一对刚出生的小兔一个月后就能长成大兔,
再过一个月就能生下一对小兔,并且此后每个月都生一对小兔,没有发生死亡,
问:现有一对刚出生的兔子2年后(24个月)会有多少对兔子?
    /*
    用递归实现不死神兔:故事得从西元1202年说起,话说有一位意大利青年,名叫斐波那契。
    在他的一部著作中提出了一个有趣的问题:假设一对刚出生的小兔一个月后就能长成大兔,
    再过一个月就能生下一对小兔,并且此后每个月都生一对小兔,没有发生死亡,
    问:现有一对刚出生的兔子2年后(24个月)会有多少对兔子?
    *注意每对小兔一个月后,才能生兔子
     1  1                   f(1)=1
     2  1                   f(2)=1
     3  2                   f(3)=2
     4  3                   f(4)=3
                            f(4)=f(3)+f(2)=3
                            f(n)=f(n-1)+f(n-2)
     */
    public static int f(int n){
        if (n<=2){
            return 1;
        }
        return f(n-1)+f(n-2);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值