JAVA⽅法中参数到底是值传递还是引⽤传递
当⼀个对象被当作参数传递到⼀个⽅法后,在此⽅法内可以改变这个对象的属性,那么这⾥到底是值传递还是引⽤传递?
答:是值传递。Java 语⾔的参数传递只有值传递。当⼀个实例对象作为参数被传递到⽅法中时,参数的值就是该对象的引⽤的⼀个副本。指向同⼀个对象,对象的内容可以在被调⽤的⽅法内改变,但对象的引⽤(不是引⽤的副本) 是永远不会改变的。
Java的参数传递,不管是基本数据类型还是引⽤类型的参数,都是按值传递,没有按引⽤传递!
对于参数的传递可以分为两种情况:
1.基本数据类型的参数
1 public class TransferTest {
2 public static void main(String[] args) {
3 int num = 1;
4 System.out.println("changeNum()⽅法调⽤之前:num = " + num);
5 changeNum(num);
6 System.out.println("changeNum()⽅法调⽤之后:num = " + num);
7 }
8
9 public static void changeNum(int x) {
10 x = 2;
11 }
12 }
运⾏结果:
传递过程的⽰意图如下:
分析:num作为参数传递给changeNum()⽅法时,是将内存空间中num所指向的那个存储单元中存放的值1复制了⼀份传递给了changeNum()⽅法中的x变量,⽽这个x变量也在内存空间中分配的⼀个存储单元。这时就把num对的值1传递给了x变量所指向的存储单元中。此后在changeNum()⽅法中对x变量的⼀切操作都是针对于x所指向的这个存储单元,与num所指向的存储单元⽆关。
所以,在changeNum()⽅法被调⽤后,num所指向的存储单元的值还是没有发⽣变化,这就是所谓的“值传递”。
值传递的精髓是:传递的是存储单元中的内容,⽽不是存储单元的引⽤。
2.引⽤类型的参数
⽰例1:
1 public class TransferTest
2 {
2 public static void main(String[] args) {
3 Person person = new Person();
4 System.out.println(person);
5 change(person);
6 System.out.println(person);
7 }
8
9 public static void change(Person p) {
10 p = new Person();
11 }
12 }
13
14 /**
15 * Person类
16 */
17 class Person {
18
19 }
运⾏结果:
可以看出两次打印结果⼀致。即调⽤change()⽅法后,person变量并没发⽣改变。
传递过程的⽰意图如下:
分析:
01.当程序执⾏到第3⾏ Person person = new Person()时,程序在堆内存(heap)中开辟了⼀块内存空间⽤来存储Person类实例对象,同时在栈内存(stack)中开辟了⼀个存储单元来存储该实例对象的引⽤,即上图中person指向的存储单元。
02.当程序执⾏到第5⾏ change(person)时,person作为参数(实参)传递给饿了change()⽅法。这⾥是person将⾃⼰的存储单元的内容传递给了change()⽅法的p变量。此后在change()⽅法中对p变量的⼀切操作都是针对于p变量所指向的存储单元,与perosn所指向的存储单元就没有关系了。
⽰例2:
1 public class P {
2 String name = "P";
3 public P(String name) {
4 this.name = name;
5 }
6 @Override
7 public String toString() {
8 return name;
9 }
10 }
11
12 public class Test {
13 static P p1 = new P("p1");
java的tostring方法14 public static void main(String[] args) {
15 P p = new P("P");
16 System.out.println("before change p:" + p.toString);
17 changeObj(p);
18 System.out.println("after change p:" + p.toString());
19 }
20
21 static void changeObj(P p) {
22 p = new P("pp");
23 System.out.println("change p:" + p.toString());
24 //p = p1;
25 //System.out.String());
26 }
27 }
运⾏结果:
⾸先要理解 “=” 赋值操作的意义:
对于基本数据类型来说 “=”赋值操作是直接改变内存地址(存储单元)上的值。
对于引⽤类型来说 “=” 赋值操作是改变引⽤变量所指向的内存地址(上⽂中存储单元)。
调⽤changeObj()⽅法进⼊第21⾏:
执⾏22⾏后:
所以对外部的p变量是没有影响的。
总结:
函数参数传递其实是⼀个赋值的过程,基本类型传递的是数值,引⽤类型传递的引⽤对象的内存地址。另外⼀点要特别注意,函数的参数其实是函数内部的局部变量。不要跟外部变量混淆。
⽰例3:
1 package cn.canshu;
2 class Person{
3 private int id;
4 private String name;
5 public Person(int id,String name) {
6 this.id = id;
7 this.name = name;
8 }
9 }
10 public class Demo02 {
11 public static void main(String[] args) {
12 Person a = new Person(23, "a");
13 Person b = new Person(22,"b");
14 System.out.println("交换前\na:"+a+"\nb:"+b);
15 swap(a, b);
16 System.out.println("交换后\na:"+a+"\nb:"+b);
17 }
18 private static void swap(Person a, Person b) {
19 Person temp = a;
20 a = b;
21 b = temp;
22 }
23 }
运⾏结果:
同理,外部的ab引⽤不是内部的ad引⽤,故不会发⽣改变。
我们可以发现,Java⽅法的传值,实际上是把实参的值—-对象引⽤(对象的内存地址)传递给了形参,从⽽形参和实参的值(即变量⾥存储的内存地址,⾮变量本⾝的内存地址)是相同的,指向了同⼀个对象/内存地址。
===================================我是分割线
==========================================================================================
⽰例4
class Person{
private int id;
private String name;
public Person(int id,String name) {
this.id = id;
this.name = name;
}
//省略get,set⽅法
//省略toString⽅法
}
public void demo(){
Person person = new Person("张三",1);
sout(person);
demo2(person);
sout(person);
}
public void demo2(Person person1){
person.setName ="李四"
person.setId=2
sout(person1)
}
运⾏结果:
改变前:person{name=‘张三’,age=1}
person{name=‘李四’,age=2}
改变后:person{name='李四',age=2}
把person对象的地址的引⽤传给了person1 ,所以person和person1指向的是同⼀个内存地址。
总结⼀下:JAVA⽅法的传值,基本数据类型是值传递,引⽤数据类型(不包含String类型)是值传递【地址值的传递】,如果⽅法⾥有person1=new Person【new对象】,或者是给对象person1赋值了⼀个地址值。原来的(person)对象不改变,如果只是改变person1的属性,person的属性值也会跟着改变。
如果有疏漏,请指正(* ̄︶ ̄)
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论