您的位置:首页 > 新闻 > 热点要闻 > Java参数传递

Java参数传递

2025/1/3 12:33:28 来源:https://blog.csdn.net/qq_41100617/article/details/141038533  浏览:    关键词:Java参数传递

Java参数传递

一、 方法重载

一个类中可以存在多个同名的方法,只要这些方法的参数列表不同即可。

  • 参数列表不同:参数个数或者参数类型不同
  • 方法重载与修饰符、返回值类型等统统无关,只看参数列表

二、 可变个数的形参

从Java5.0开始,Java有了可变形参的语法,即形参的类型可以确定,但是形参的个数不确定

可变形参的格式:方法名(参数类型... 参数名)

比如:

public void f(int i, String... strings) {for (String string : strings) {System.out.println(string);}
}

此时,调用方法f时,可以传入1个或多个字符串,甚至可以不传入字符串。比如:

f(0); // 不传入字符串
f(1, "one"); // 传入1个字符串
f(2, "one", "two"); //入多个字符串

注:

  • 可变形参等价于使用数组形参,因此当两个方法一个使用可变形参、一个使用数组且其他参数列表相同时,将会报错。比如下面的语句将会报错:

    public void f(int i, String... strings) {}public void f(int i, String[] strings) {}
    
  • 可变形参需要放在方法参数列表的最后

  • 在一个方法中,最多只能声明一个可变形参

三、 值传递

3.1 两种传递方式

参数传递有引用传递以及值传递两种方式:

  • 引用传递,在调用方法时将参数的地址直接传递到方法中
  • 值传递,在调用方法时将参数的值拷贝一份传递到方法中

3.2 Java参数传递类型

Java在传递参数时,只有值传递这一种方式。从JVM层面来看,Java在传递参数时是将栈中变量的值拷贝一份传递给参数。

3.2.1 传递基本类型

当传递基本类型时,将基本类型的数值直接拷贝一份传递给方法,在方法内部对参数做的修改并不会影响到方法外部。比如:

public class Main {public static void main(String[] args) {int i = 10;System.out.println("调用 test 方法前 i 的值:" + i);test(i);System.out.println("调用 test 方法后 i 的值:" + i); // test 方法并不会修改 i 的值}public static void test(int m) {m = 20;}
}

调用test方法时,main方法将整形变量i的值10拷贝赋值给参数m(这相当于初始化test方法内部的变量m),在test内部对变量m的改动并不会影响main方法中的变量i

3.2.2 传递引用类型

引用类型与基本类型在内存中的存储方式略有不同:

  • 基本类型在栈中存放的是变量具体的值
  • 引用类型在栈中存放了一个地址,该地址指向堆中的某块内存区域,而该内存区域才是真正存放对象的地方
public class Main {public static void main(String[] args) {int i = 0;User user = new User(16, "main");}
}class User {public int age;public String name;public User(int age, String name) {this.age = age;this.name = name;}
}

比如,上面这段代码,main方法中有两个局部变量,一个是整形变量i,一个是引用类型user,这两个变量在内存中的分布如下图所示:

请添加图片描述

引用类型的这种存储特点使得其在参数传递时产生了一些副作用:

  1. 与传递基本类型一样,当传递引用类型时,将引用类型的数值直接拷贝一份传递给方法,此时不会影响到存放在栈中的值。比如:

    public class Main {public static void main(String[] args) {User user = new User(16, "main");System.out.println("调用 f1 方法前 user 的值:" + user);f1(user);System.out.println("调用 f1 方法后 user 的值:" + user); // user的值不会发生改变}public static void f1(User userArg) {userArg = new User(20, "f2");System.out.println("f1:" + userArg);}
    }class User {public int age;public String name;public User(int age, String name) {this.age = age;this.name = name;}
    }
    

    从输出结果可以看到,与传递基本类型一样,在调用f1方法前后user的值不会发生改变。

  2. 虽然不会影响到存放在栈中的值,但是会影响到堆中的值。比如:

    public class Main {public static void main(String[] args) {User user = new User(16, "main");System.out.println("调用 f2 方法前 user 的值:" + user.age + user.name);f2(user);System.out.println("调用 f2 方法后 user 的值:" + user.age + user.name); // user所指向的对象发生了改变}public static void f2(User userArg) {userArg.age = 18;userArg.name = "f2";}
    }class User {public int age;public String name;public User(int age, String name) {this.age = age;this.name = name;}
    }
    

    从输出结果可以看到,在调用f2方法后user对象的成员变量值发生了改变。这是因为虽然值传递是拷贝,但是useruserArg指向的地址是同一个,所以方法内部对引用类型内部的成员变量进行修改时,还是会影响到堆中的值。此时,useruserArg在内存中的存储情况如下:

    请添加图片描述

四、 笔/面试题目

  1. 问:Java是值传递还是引用传递

    答:Java是值传递

  2. 问:下面代码执行完之后,数组ints的元素值是多少

    public class Main {public static void main(String[] args) {int[] ints = new int[]{1, 2, 3};f(ints);}public static void f(int[] intsArg) {for (int i = 0; i < intsArg.length; i++) {intsArg[i] += 10;}}
    }
    

    答:数组也是一种引用类型,当调用方法f时,参入的是数组ints在栈中的值,该值指向堆中存存放数组具体内容的内存区域。当在方法f内部对数组内容进行操作时,将会修改堆中的内容,而由于intsintsArg指向同一块堆内存,因此ints所指向的数组也会被修改。因此最终数组ints的元素值是11、12、13

  3. 问:下面代码执行完之后,数组ints的元素值是多少

    public class Main {public static void main(String[] args) {int[] ints = new int[]{1, 2, 3};f(ints);}public static void f(int[] intsArg) {for (int i : intsArg) {i += 10;}}
    }
    

    答:这题与上题相识,但在方法f内部遍历数组的方式却不同:

    • 上一题是通过一个递增的变量i依次访问数组中的元素并修改元素的值
    • 本题是通过foreach语法依次取出数组中的元素值并将其赋值给一个新的变量i,然后修改这个变量i。修改的是变量i,并未对数组元素做修改

    因此最终数组ints的元素值仍然是1、2、3

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com