JavaSE_day07_类的成员之方法(method)

方法概述

什么是方法(method、函数):

  • 方法是类或对象行为特征的抽象,用来完成某个功能操作。在某些语言中 也称为函数或过程。
  • 将功能封装为方法的目的是,可以实现代码重用,简化代码
  • Java里的方法不能独立存在,所有的方法必须定义在类里。

            ​ 

对于上面的语法格式中具体说明如下:

  • 修饰符方法的修饰符比较多,有对访问权限进行限定的,有静态修饰符static,还有最终修饰符final等,
  • 返回值类型用于限定方法返回值的数据类型
  • 参数类型用于限定调用方法时传入参数的数据类型
  • 形参名:是一个变量,用于接收调用方法时传入的数据
  • return关键字两个作用,第一停止当前方法,第二将后面的返回值还给调用处。返回值:也就是方法执行后最终产生的数据结果
  • 返回值:被return语句返回的值,该值会返回给调用者

需要特别注意的是,方法中的“参数类型 形参名1,参数类型 形参名2”被称作参数列表,它用于描述方法在被调用时需要接收的参数,如果方法不需要接收任何参数,则参数列表为空,即()内不写任何内容。方法的返回值必须为方法声明的返回值类型,如果方法中没有返回值,返回值类型要声明为void,此时,方法中return语句可以省略。

  • 形参:方法定义中的参数
  • 实参:方法调用中的参数 

方法的分类

 

定义方法时,要做到两个明确

  • 明确返回值类型:主要是明确方法操作完毕之后是否有数据返回,如果没有,写void;如果有,写对应的数据类型 
  • 明确参数:主要是明确参数的类型和数量 

方法调用的三种形式

  • 直接调用:直接写方法名调用
  • 赋值调用:调用方法,在方法前面定义变量,接收方法返回值
  • 输出语句调用: 在输出语句中调用方法, System.out.println(方法名()) 

调用方法时的注意:

  • void类型的方法,直接调用即可
  • 非void类型的方法,推荐用变量接收调用

代码举例

package demo02;

/*
方法其实就是若干语句的功能集合。

参数(原料):就是进入方法的数据。
返回值(产出物):就是从方法中出来的数据。

定义方法的完整格式:
修饰符 返回值类型 方法名称(参数类型 参数名称, ...) {
    方法体
    return 返回值;
}

修饰符:现阶段的固定写法,public static
返回值类型:也就是方法最终产生的数据结果是什么类型
方法名称:方法的名字,规则和变量一样,小驼峰
参数类型:进入方法的数据是什么类型
参数名称:进入方法的数据对应的变量名称
PS:参数如果有多个,使用逗号进行分隔
方法体:方法需要做的事情,若干行代码
return:两个作用,第一停止当前方法,第二将后面的返回值还给调用处
返回值:也就是方法执行后最终产生的数据结果

注意:return后面的“返回值”,必须和方法名称前面的“返回值类型”,保持对应。

定义一个两个int数字相加的方法。三要素:
返回值类型:int
方法名称:sum
参数列表:int a, int b

方法的三种调用格式。
1. 单独调用:方法名称(参数);
2. 打印调用:System.out.println(方法名称(参数));
3. 赋值调用:数据类型 变量名称 = 方法名称(参数);

注意:此前学习的方法,返回值类型固定写为void,这种方法只能够单独调用,不能进行打印调用或者赋值调用。
*/
public class Demo02MethodDefine {

    public static void main(String[] args) {
        // 单独调用
        sum(10, 20);
        System.out.println("===========");

        // 打印调用
        System.out.println(sum(10, 20)); // 30
        System.out.println("===========");

        // 赋值调用
        int number = sum(15, 25);
        number += 100;
        System.out.println("变量的值:" + number); // 140
    }

    public static int sum(int a, int b) {
        System.out.println("方法执行啦!");
        int result = a + b;
        return result;
    }

}

方法使用的注意事项

  • 方法应该定义在类当中,但是不能在方法当中再定义方法。不能嵌套。
  • 方法定义的前后顺序无所谓。
  • 方法定义之后不会执行,如果希望执行,一定要调用:单独调用、打印调用、赋值调用。
  • 如果方法有返回值,那么必须写上“return 返回值;”,不能没有。return语句后面不能跟数据或代码 
  • return后面的返回值数据,必须和方法的返回值类型,对应起来。
  • 对于一个void没有返回值的方法,不能写return后面的返回值,只能写return自己。
  • 对于void方法当中最后一行的return可以省略不写。
  • 一个方法当中可以有多个return语句,但是必须保证同时只有一个会被执行到,两个return不能连写。
package demo03;

/*
使用方法的时候,注意事项:

1. 方法应该定义在类当中,但是不能在方法当中再定义方法。不能嵌套。
2. 方法定义的前后顺序无所谓。
3. 方法定义之后不会执行,如果希望执行,一定要调用:单独调用、打印调用、赋值调用。
4. 如果方法有返回值,那么必须写上“return 返回值;”,不能没有。
5. return后面的返回值数据,必须和方法的返回值类型,对应起来。
6. 对于一个void没有返回值的方法,不能写return后面的返回值,只能写return自己。
7. 对于void方法当中最后一行的return可以省略不写。
8. 一个方法当中可以有多个return语句,但是必须保证同时只有一个会被执行到,两个return不能连写。
 */
public class Demo04MethodNotice {

    public static int method1() {
        return 10;
    }

    public static void method2() {
//        return 10; // 错误的写法!方法没有返回值,return后面就不能写返回值。
        return; // 没有返回值,只是结束方法的执行而已。
    }

    public static void method3() {
        System.out.println("AAA");
        System.out.println("BBB");
//        return; // 最后一行的return可以省略不写。
    }
    
}

方法重载

法重载指同一个类中定义的多个方法之间的关系,满足下列条件的多个方法相互构成重载

  • 多个方法在同一个类中
  • 多个方法具有相同的方法名
  • 多个方法的参数不相同,类型不同或者数量不同

重载的特点:

  • 与返回值类型无关,只看参数列表,且参数列表必须不同。(参数个数或参数类 型)。调用时,根据方法参数列表的不同来区别。

示例:

/*
 * 方法的重载(overload)  loading...
 * 
 * 1.定义:在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。
 *     
 *  "两同一不同":同一个类、相同方法名
 *            参数列表不同:参数个数不同,参数类型不同
 * 
 * 2. 举例:
 *    Arrays类中重载的sort() / binarySearch()
 * 
 * 3.判断是否是重载:
 *    跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!
 *    
 * 4. 在通过对象调用方法时,如何确定某一个指定的方法:
 *      方法名 ---> 参数列表
 */
public class OverLoadTest {
    public static void main(String[] args) {
        
        OverLoadTest test = new OverLoadTest();
        test.getSum(1,2);
        
        
    }
    
    //如下的4个方法构成了重载
    public void getSum(int i,int j){
        System.out.println("1");
    }
    
    public void getSum(double d1,double d2){
        System.out.println("2");
    }
    
    public void getSum(String s ,int i){
        System.out.println("3");
    }
    
    public void getSum(int i,String s){
        System.out.println("4");
    }
    
    //如下的3个方法不能与上述4个方法构成重载
//    public int getSum(int i,int j){
//        return 0;
//    }
    
//    public void getSum(int m,int n){
//        
//    }
    
//    private void getSum(int i,int j){
//        
//    }
    
    
}

方法调用时参数的传递问题

方法在调用的时候参数是如何传递的呢?其实在调用的时候参数传递给方法,这个过程就是赋值的过程,参数传递和“赋值规则”完全相同,只不过参数传递在代码上看不见“=”运算符。我们先来深入的研究一下“赋值规则”吧! 我们知道“赋值”运算的时候实际上和变量的数据类型无关,无论是基本数据类型还是引用数据类型,一律都是将变量中保存的“值”复制一份,然后将复制的这个“值”赋上去。他们的区别在于,如果是基本数据类型则和堆内存当中的对象无关,如果是引用数据类型由于传递的这个值是 java 对象的内存地址,所以会导致两个引用指向同一个堆内存中的 java 对象,通过任何一个引用去访问堆内存当中的对象,此对象内存都会受到影响。

方法参数传递基本类型

  • 基本数据类型的参数,形式参数的改变,不影响实际参数

依据:

  • 每个方法在栈内存中,都会有独立的栈空间,方法运行结束后就会弹栈消失

                                     

代码举例

public class Demo {
 
        public static void main(String[] args) {
            int number = 100;
            System.out.println("调用change方法前:" + number);//调用change方法前:100
            change(number);
            System.out.println("调用change方法后:" + number);//调用change方法后:100
        }
 
        public static void change(int number) {
            number = 200;
        }
    }

方法参数传递引用类型

结论:

  • 对于引用类型的参数,形式参数的改变,影响实际参数的值

依据:

  • 引用数据类型的传参,传入的是地址值,内存中会造成两个引用指向同一个内存的效果,所以即使方法 弹栈,堆内存中的数据也已经是改变后的结果

示例

public class Demo {
 
    public static void main(String[] args) {
        int[] arr = {10, 20, 30};
        System.out.println("调用change方法前:" + arr[1]);//调用change方法前:20
        change(arr);
        System.out.println("调用change方法后:" + arr[1]);//调用change方法后:200
    }
 
    public static void change(int[] arr) {
        arr[1] = 200;
    }
 
}

变量的赋值:

  • 如果变量是基本数据类型,此时赋值的是变量所保存的数据值。
  • 如果变量是引用数据类型,此时赋值的是变量所保存的数据的地址值。

值传递机制:

  • 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。
  • 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值

方法递归

递归:

  • 递归其实就是方法在执行的过程中调用了另一个方法,而另一个方法则是自己本身。

递归的分类:

  • 递归分为两种,直接递归和间接递归。
  • 直接递归称为方法自身调用自己。
  • 间接递归可以A方法调用B方法,B方法调用C方法,C方法调用A方法。

注意事项:

  • 递归一定要有条件限定,保证递归能够停止下来,否则会发生栈内存溢出。
  • 在递归中虽然有限定条件,但是递归次数不能太多。否则也会发生栈内存溢出。
  • 构造方法,禁止递归

代码举例

/*
    方法递归?
        1、什么是方法递归?
            方法自己调用自己,这就是方法递归。

        2、当递归时程序没有结束条件,一定会发生:
            栈内存溢出错误:StackOverflowError
            所以:递归必须要有结束条件。(这是一个非常重要的知识点。)

            JVM发生错误之后只有一个结果,就是退出JVM。

        3、递归假设是有结束条件的,就一定不会发生栈内存溢出错误吗?
            假设这个结束条件是对的,是合法的,递归有的时候也会出现栈内存溢出错误。
            因为有可能递归的太深,栈内存不够了。因为一直在压栈。
        
        4、在实际的开发中,不建议轻易的选择递归,能用for循环while循环代替的,尽量
        使用循环来做。因为循环的效率高,耗费的内存少。递归耗费的内存比较大,另外
        递归的使用不当,会导致JVM死掉。
        (但在极少数的情况下,不用递归,这个程序没法实现。)
        所以:递归我们还是要认真学习的。

        5、在实际的开发中,假设有一天你真正的遇到了:StackOverflowError
        你怎么解决这个问题,可以谈一下你的思路吗?
            我来谈一下我的个人思路:
                首先第一步:
                    先检查递归的结束条件对不对。如果递归结束条件不对,
                    必须对条件进一步修改,直到正确为止。

                第二步:假设递归条件没问题,怎么办?
                    这个时候需要手动的调整JVM的栈内存初始化大小。
                    可以将栈内存的空间调大点。(可以调整大一些。)
                
                第三步:调整了大小,如果运行时还是出现这个错误,
                没办法,只能继续扩大栈的内存大小。
                
                (java -X)这个可以查看调整堆栈大小的参数
*/

// 使用递归,请编写程序,计算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
    }

    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);
    }
}
原文地址:https://www.cnblogs.com/wurengen/p/13456981.html