天真,居然还有人认为 java 的参数传递方式是引用传递 (1)
public static void main(String[] args) {
int a = 1;
dosomthing(a);
System.out.println("主函数 a 的值 = "+a);
}
private static void dosomthing(int a) {
a = a-1;
System.out.println("修改过后,a = "+a);
}
}
这是一个很简单的一个方法,在主函数 main 中对变量进行了初始化 a=1,然后将 a 传递给 dosomthing(),然后再 dosomthing 中输出了修改之后的值,最后在主函数中打印 a 的值,你们觉得这几句输出中 a 的值分别是多少呢?
第一种:
修改过后,a = 0
主函数 a 的值 = 1
第二种:
修改过后,a = 0
主函数 a 的值 = 0
第三种:
修改过后,a = 1
主函数 a 的值 = 1
想要得到答案的话就得先明白参数传递的两个类型:值传递和引用传递。
什么是引用传递?
在 C++中,函数参数的传递方式有引用传递。所谓引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
什么是值传递?
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
我们再回过头来看上面的例子,如果是引用传递的话打印结果应该是第二种情况,如果是值传递,打印结果应该是第一种情况,所以到底打印的结果是什么呢?
我们一起看一看控制台输出
Connected to the target VM, address: '127.0.0.1:59333', transport: 'socket'
修改过后,a = 0
主函数 a 的值 = 1
Disconnected from the target VM, address: '127.0.0.1:59333', transport: 'socket'
Process finished with exit code 0
这就是第一种情况,很明显,在 dosomthing 函数中修改了 a 的值,但是主函数中的 a 并没有受到影响,所以肯定不会是引用传递,如果是引用传递,主函数的 a 应该会变成 0,只有在参数传递的时候将主函数的中参数复制一份给 dosomthing,才能在 dosomthing 中修改 a 不会对主函数造成影响,所以从基本数据类型来看,java 的参数传递方式为:值传递。
这个时候你可能会有疑问了,这只是基本数据类型的传递方式,其他的参数类型呢?下面我们一起来看看引用类型和对象类型的传递方式。
follow me !!!!!
[](
)引用类型传递
=====================================================================
我们都知道 java 中的 String 类型不属于基本数据类型,它是一个引用类型,也可以说是一个对象,那么它的传递方式是什么呢?
我们还是先来看例子
package com.ymy.param;
/**
@ProjectName: demo
@Package: com.ymy.param
@ClassName: StringTypeTest
@Author: 流星 007
@Description: String 类型传递
csdn:https://blog.csdn.net/qq_33220089
今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
@Date: 2020/7/5 14:22
@Version: 1.0
*/
public class StringTypeTest {
public static void main(String[] args) {
String a = "hello";
dosomthing(a);
System.out.println("主函数 a 的值 = "+a);
}
private static void dosomthing(String a) {
a = a+" bug";
System.out.println("修改过后,a = "+a);
}
}
打印结果
修改过后,a = hello bug
主函数 a 的值 = hello
Process finished with exit code 0
我们发现主函数的 a 并没有受到 dosomthing 函数的影响,所以这并不是引用传递,这个时候你说是因为
a = a+" bug";这行代码生成了新的对象,所以才会导致数据不一致,我们先来看看 a 的赋值情况吧
// class version 52.0 (52)
// access flags 0x21
public class com/ymy/param/StringTypeTest {
// compiled from: StringTypeTest.java
// access flags 0x1
public <init>()V
L0
LINENUMBER 14 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
RETURN
L1
LOCALVARIABLE this Lcom/ymy/param/StringTypeTest; L0 L1 0
MAXSTACK = 1
MAXLOCALS = 1
// access flags 0x9
public static main([Ljava/lang/String;)V
// parameter args
L0
LINENUMBER 17 L0
LDC "hello"
ASTORE 1
L1
LINENUMBER 18 L1
ALOAD 1
INVOKESTATIC com/ymy/param/StringTypeTest.dosomthing (Ljava/lang/String;)V
L2
LINENUMBER 19 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "\u4e3b\u51fd\u6570a\u7684\u503c = "
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 1
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L3
LINENUMBER 21 L3
RETURN
L4
LOCALVARIABLE args [Ljava/lang/String; L0 L4 0
LOCALVARIABLE a Ljava/lang/String; L1 L4 1
MAXSTACK = 3
MAXLOCALS = 2
// access flags 0xA
private static dosomthing(Ljava/lang/String;)V
// parameter a
L0
LINENUMBER 24 L0
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
ALOAD 0
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
LDC " bug"
INVOKEVIRTUAL ja
va/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
ASTORE 0
L1
LINENUMBER 25 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
NEW java/lang/StringBuilder
DUP
INVOKESPECIAL java/lang/StringBuilder.<init> ()V
LDC "\u4fee\u6539\u8fc7\u540e\uff0ca = "
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
ALOAD 0
INVOKEVIRTUAL java/lang/StringBuilder.append (Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString ()Ljava/lang/String;
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L2
LINENUMBER 27 L2
RETURN
L3
LOCALVARIABLE a Ljava/lang/String; L0 L3 0
MAXSTACK = 3
MAXLOCALS = 1
}
这是上面代码的字节码代码,我们可以清楚的看到 a 在赋值的时候都调用了 StringBuilder 的同 String 方法,现在我们来看看这个神奇的同 String 方法。
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
这是 StringBuilder 中的 toString 方法,确实是 new 了一个新的对象,就算是 a 变成了一个新的对象,如果是引用传递,主函数的 a 就不会受影响吗?这点我会讲完对象类型传递之后在进行讲解,请继续往下看。
[](
)对象类型传递
=====================================================================
其实上面的两种其实很好区分,很多人都知道是值传递,很多人说 java 的传递方式是引用传递的原因就是出自这里:传递的参数为对象。
有些人看到对象传递的时候会改变主函数的值,就认为 java 的参数传递是引用传递,有些人又因为基本数据类型不会队主函数的值造成修改,所以他们的结论是:基本数据类型为值传递;对象类型为引用传递,想法很好,那我们现在一起来解开对象传递的神秘面纱,它到底是引用传递还是值传递呢?
go go go !!!!
还是老规矩,我们一起来看一个例子
package com.ymy.param.vo;
/**
@ProjectName: demo
@Package: com.ymy.param.vo
@ClassName: LolVo
@Author: 流星 007
@Description: lol 英雄属性
csdn:https://blog.csdn.net/qq_33220089
今日头条:https://www.toutiao.com/c/user/5372182357/#mid=1637641735275523
@Date: 2020/7/5 15:11
@Version: 1.0
*/
public class LolVo {
/**
姓名
*/
private String name;
/**
职业
*/
private String profession;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getProfession() {
return profession;
}
public void setProfession(String profession) {
this.profession = profession;
}
@Override
public String toString() {
return "LolVo{" +
评论