Java方法

370 阅读10分钟

定义

Java的方法类似于其他语言的函数,是一段用来完成特定功能的代码片段

方法包含一个方法头和一个方法体。

  • 修饰符:可选,定义方法的 访问范围 和 访问方式 。初期暂且固定书写为 public static
  • 返回值类型:方法返回值的数据类型。方法没有返回值,则返回值类型为 void
  • 方法名:方法的自定义名称,方法名与参数列表共同构成方法签名,命名遵循 标识符命名规范
  • 形参列表:可选,指定每个传入参数的类型及名字 [参数类型 参数名]。方法可以不包含任何参数,如果参数有多个,中间用逗号分隔
    • 形参:在方法被调用时用于接收外界输入的数据
    • 实参:调用方法时实际传给方法的数据
  • 方法体:方法体包含具体的语句,定义该方法的功能

语法格式

基本格式
修饰符列表 返回值类型 方法名(形参列表){  //修饰符作用是访问权限
   方法体...
   return 返回值;
}

格式1 —— 带参数方法的定义
public static void 方法名(形参列表){  //分带与不带static的
//方法内容
}

格式2 —— 带返回值的参数方法定义
public 返回类型 方法名(形参列表){  //分带与不带static的
//方法定义的实现
}

其中static说明这是静态方法。
静态成员和静态方法只能访问静态成员和静态方法,若要访问非静态成员和非静态方法,则需要通过创建对象来访问,形如 类名 标识符=new 类名(); 而非静态的成员既可以访问静态成员和静态方法也可以访问非静态成员和非静态方法。


调用

语法格式

方法名(实参列表); 
  • 无参方法调用时将(实参列表)省略
  • 调用时,参数 可以是 常数变量表达式,包括 基本数据类型、对象类型(可以是自定义的类或Java标准库中的类),多个参数之间用逗号分隔
  • 调用方法和定义方法时 的参数和参数类型要 一 一对应

调用方式

//max(x, y)是一个返回参数x y中最大值的方法

//方法作为表达式中的一项出现在表达式中
z = max(x, y);
m = n + max(x, y);

//方法作为一个单独的语句
System.out.print(a);  //System.out.print 方法打印输出 a
Scanner scanner = new Scanner(System.in);
int b = scanner.nextInt();  //Scanner.nextInt 方法从标准输入中读取下一个整数

//方法作为调用另一个方法时的实参
System.out.print(Math.max(x, y));  //调用 System.out.print 方法打印输出max(x, y)的返回值
total(Math.max(x, y), Math.min(m, n));  //调用了一个名为total的方法,并将 max(x, y)和 min(m, n)的返回值 作为参数传递给这个方法

使用类名、对象名来调用方法

类名

在Java中,如果在不同的类中调用方法,或者在实例方法中调用静态方法,则需要使用类名来调用方法。

使用类名调用类中的方法

ClassName.methodName();
//ClassName是 调用的方法所在的 类的名称,methodName()是 被调用的方法的名称

示例:

public class MyClass {
  public static void myMethod() {
    System.out.println("This is MyClass.myMethod");
  } 
} 
public class AnotherClass { 
  public static void main(String[] args) {
    MyClass.myMethod(); // 使用类名调用MyClass中的myMethod方法 
  } 
}

对象名

在Java中,如果在类中调用实例方法,或者在静态方法中调用实例方法,则需要使用对象名来调用方法。

步骤:

  1. 在调用前通过使用 new 关键字创建一个 被调用的方法所在类 的实例对象
ClassName objectName = new ClassName();
//ClassName是 要创建实例对象的 类的名称,objectName是创建的实例对象的名称
  1. 使用对象来调用其方法
objectName.methodName(); // 调用对象的方法  
//methodName()是 被调用的实例方法的名称

示例:

public class MyClass { 
  public void myMethod() {
    System.out.println("This is MyClass.myMethod"); 
  } 
public static void main(String[] args) {
  MyClass obj = new MyClass();  // 创建一个MyClass的实例 
    obj.myMethod();  // 使用对象名调用实例方法myMethod
  } 
}

拓展

  • 方法可以嵌套调用,也就是在一个方法的定义调用过程中允许出现对另外一个方法的调用

  • 如果一个方法 A() 在定义或调用过程中出现了对另外一个方法 B() 的调用,那么我们就称 A() 为主调方法或主方法,称 B() 为被调方法

  • 当执行主调方法中执行到其中的被调方法时,主调方法会暂停,CPU 转而执行被调方法的代码;被调方法执行完毕后再返回主调方法,主调方法根据被调方法的返回值继续往下执行

  • 一个Java程序的执行过程可以认为是多个方法之间的相互调用过程,它们形成了一个方法调用栈(调用链条)。这个链条的起点是 main(),终点也是 main()

    实际上,Java程序的执行可以从任何非静态的、非构造的方法开始,只要该方法被调用,而不仅仅是从main方法开始和结束

  • 参数传递方式

    值传递是指在调用方法时将实际参数复制一份传递到方法中,这样在方法中如果对参数进行修改,将不会影响到实际参数。

参数传递

Java中方法的参数都是值传递

值传递:在方法被调用时,将实参的内容复制一份传入方法中,此时形参接收到的内容是实参值的一个拷贝,因此在方法内对形参的任何操作,都仅仅是对这个副本的操作,不影响实参值。
引用传递:在方法被调用时,将实参的地址直接传入方法中,那么在方法中对参数所进行的修改,将影响到实参。

在 Java 中,对引用类型的数据进行操作可以分为两种情况:

  1. 形参和实参保持指向同一个对象地址
  2. 形参被改动指向新的对象地址,如重新赋值引用

形参和实参保持指向同一个对象地址(影响实参)

当形参和实参指向同一个对象地址时,在方法中对形参进行的操作会影响实参指向的对象的内容。这是因为引用类型的参数传递的是对象的引用地址,即形参和实参指向的是同一个对象

public class Main {
    public static void modifyArray(int[] arr) {
        arr[0] = 100;    //对传入数组的第一个元素赋值为100
    }

    public static void main(String[] args) {
        int[] originalArr = {1, 2, 3};
        modifyArray(originalArr);  //调用originalArr方法,传入originalArr数组参数
        //在modifyArray中,arr 和 originalArr 实际上指向同一块内存地址
        System.out.println(Arrays.toString(originalArr)); // 输出 [100, 2, 3]
    }
}

形参被改动指向新的对象地址(不影响实参)

如果在方法内部将形参重新赋值为指向新的对象地址,那么形参的操作不会影响实参指向的对象的内容。这是因为重新赋值引用后,形参将指向一个新的对象,与传入实参对象无关

public class Main {
    public static void replaceArray(int[] arr) {
        arr = new int[]{4, 5, 6};  // arr 被重新赋值指向了一个新的数组对象
    }

    public static void main(String[] args) {
        int[] originalArr = {1, 2, 3};
        replaceArray(originalArr);
        System.out.println(Arrays.toString(originalArr)); // 输出 [1, 2, 3]
    }
}

返回值

方法的返回值是指 方法被调用之后,执行 方法体中的程序段所取得并返回给主调方法的值

  • 方法的返回值可以是任意数据类型,包括基本数据类型和引用数据类型
  • 方法的返回值类型必须与方法的定义相匹配
  • 方法一旦执行到 return 语句就会立即返回,return 语句后面的所有语句都不会被执行
  • void 函数中的 return 语句只能起到结束 void 函数的功能。其格式为:return;
  • 为了使程序有良好的可读性并减少出错, 凡不要求返回值的函数都应定义为 void 类型

方法的重载

方法重载是指在一个类中定义多个同名的方法,但每个方法具有不同的参数的类型或参数的个数。

通常用于创建完成一组任务相似但参数的类型或参数的个数不同的方法。

方法重载的规则

  • 方法名称必须相同
  • 参数列表必须不同(参数个数、类型、类型排列顺序至少有一个不同)
  • 与修饰符、返回值类型、参数的名称无关

实现原理
方法名相同时,编译器会根据调用方法的参数列表去逐个匹配,以选择相适的方法执行,如果匹配失败(未找到对应方法),则编译器报错。

注意: 排列顺序不同是两个数据类型排列顺序,而不是参数名,参数名的取值是任意的。如下所示:

public static void add(float f,int i)  //初始方法
public static void add(float i,int f)  //错误的 类型排列顺序不同重载
public static void add(int i,float f)  //正确的 类型排列顺序不同重载 

命令行传参

通过命令行方式向 Java 程序传递参数。我们可以通过 main 方法的参数来接收这些参数。

public static void main(String[] args) {  
    //String[] args 是一个字符串数组,用于存储从命令行传递给程序的参数
    for (int i = 0; i < args.length; i++) {  //args.length 数组长度
        System.out.println("args["+i+"]: "+args[i]);  //字符串连接操作
        //args[ 和 ] 表示字符串,args[i] 表示args数组的第 i 个元素
    }
}

运行这段代码时,可以在命令行中回退到src目录,输入Javac [文件名.java] → 回车 → 输入Java [文件名(无后缀)] [参数] → 回车 → 输出结果

可变参数

语法格式:数据类型...[空格]变量名

使用 可变参数 定义方法后,方法可以在调用时传入0~n个参数

注意:

  • 当形参中既有 可变参数,也有 普通的参数,必须确保可变参数在形参列表的最后
  • 每个形参列表最多只能有一个可变参数
  • 可变参数的本质是 一个数组,可以当作数组来用
  • 若num为一个可变参数的变量名,则能用 num[i] 在 使用可变参数定义的方法内部 表示调用时传入的第i+1个元素

示例:

//打印最大值
public static void printMax(int... num){  //接受一个可变参数 num
    if(num.length==0){    //检查传递的整数数量是否为0。如果是,则进入该if语句块。
        System.out.println("没有值传入");
        return;
    }
    int result = num[0];   //假设第一个整数是最大值并将其赋值给`result`变量
    for (int i = 1; i < num.length; i++) {   //从第二个整数开始(索引为1)遍历所有的整数
        if(num[i] > result){
            result = num[i];
        }
    }
    System.out.println("最大值是:"+result);
}
public static void main(String[] args) {
    printMax(1,2,3,4); //最大值是:4
    printMax(new int[]{1,2,3,4,5}); //最大值是:5
}

递归

递归:在定义方法时,又调用了这个方法本身

  • 形式
    直接递归:方法自己调用自己
    间接递归:方法A调用其他方法,其他方法又回调方法A
  • 执行递归函数将反复调用其自身,每调用一次就进入新的一层
  • 递归函数必须有结束条件
//阶乘 n! n*(n-1)*...*2*1
public static int f(int n){
    if(n==1) return 1;
    return n*f(n-1); 
}
public static void main(String[] args) {
    System.out.println(f(3)); 
}

运行过程图示(n取3):

微信图片_20240123223102.jpg