java实现变量值传递_JAVA值传递和引用传递的争论

JAVA值传递和引用传递的争论

今天一起秋招的小伙伴说面试官问了JAVA值传递和引用传递的问题,我不假思索的说是引用传递,结果引来一系列的讨论。但是以下几点是得到了共同的认识的:如果是值传递,那么函数调用过程中对目标的改变不会导致原来目标发生变化,类似于c++里面的swap(int a, int b)函数,在运行函数过程中,内部的a,b实际上是外部a,b的一个拷贝,改变不会传递到外部。

如果是引用传递,在函数内部的改变会影响外部的值,似于c++里面的swap(int &a, int &b),在运行函数过程中会改变外部的值。

实际上c++还有一种传递是指针传递,实际上是指针变量的值传递,这个不谈。那么JAVA里面的变量到底是值传递还是引用传递呢?我们分以下两种情况讨论:

1、基本类型变量的函数调用,这里面用int 和float作为主要的类型,代码如下:package com.lixiande.leetcode;

public class test {

public static void vallueCrossTest(int age , float weight){

System.out.println("函数内的age 地址" + System.identityHashCode(age));

System.out.println("函数内的weight 地址" + System.identityHashCode(weight));

age = 33;

weight = 89.5f;

System.out.println("函数内改变的age 地址" + System.identityHashCode(age));

System.out.println("函数内改变的weight 地址" + System.identityHashCode(weight));

}

public static void main(String[] args) {

int age = 10;

float weight = 10.01f;

System.out.println("函数外的age 地址" + System.identityHashCode(age));

System.out.println("函数外的weight 地址" + System.identityHashCode(weight));

vallueCrossTest(age,weight);

System.out.println("函数外改变的age 地址" + System.identityHashCode(age));

System.out.println("函数外改变的weight 地址" + System.identityHashCode(weight));

}

}

在函数调用前后分别获取对应参数的地址值(这里用System.identityHashCode代替),结果如下:函数外的age 地址728890494

函数外的weight 地址1558600329

函数内的age 地址728890494

函数内的weight 地址636718812

函数内改变的age 地址445051633

函数内改变的weight 地址1051754451

函数外改变的age 地址728890494

函数外改变的weight 地址1349277854

可以看到函数传递过程中的地址是不变的,但是对于基本类型int改变了他的值会导致指向的地址发生改变,这个是因为常量池的原因,常量池会维护1-127的int值。而float类型对象则是发生了多次改变,分别是从1558600329->636718812->1051754451->1349277854,float没有常量池,会在栈上找有没有相等的字面量,没有就会在栈上新开辟,所以地址发生了变化。

2、类对象的函数调用

这里面使用一个person类作为测试类,同样使用System.identityHashCode作为地址判断:package com.lixiande.leetcode;

class person{

private String name;

public person(String name){

System.out.println("now i am init a new person");

this.name = name;

}

public void setName(String name) {

this.name = name;

}

@Override

public String toString() {

return "person{" +

"name='" + name + '\'' +

'}';

}

}

public class test {

public static void personCrossTest(person p ){

System.out.println("函数内的p 地址" + System.identityHashCode(p));

p.setName("lixiang");

System.out.println("函数内改变的p 地址" + System.identityHashCode(p));

}

public static void main(String[] args) {

person p = new person("松哥哥");

System.out.println(p.toString());

System.out.println("函数外的p 地址" + System.identityHashCode(p));

personCrossTest(p);

System.out.println("函数外的改变后p 地址" + System.identityHashCode(p));

System.out.println(p.toString());

}

}

结果如下:now i am init a new person

person{name='松哥哥'}

函数外的p 地址1775282465

函数内的p 地址1775282465

函数内改变的p 地址1775282465

函数外的改变后p 地址1775282465

person{name='lixiang'}

首先,函数内外地址发生改变了吗?没有,也就是内部的person指向的和外部person指向的对象没有发生改变。这里面加入修改函数内person指向的方式进行操作,将函数修改为public static void personCrossTest(person p ){

System.out.println("函数内的p 地址" + System.identityHashCode(p));

p = new person("lixiang");

System.out.println("函数内改变的p 地址" + System.identityHashCode(p));

}

结果为:now i am init a new person

person{name='松哥哥'}

函数外的p 地址1775282465

函数内的p 地址1775282465

now i am init a new person

函数内改变的p 地址1147985808

函数外的改变后p 地址1775282465

person{name='松哥哥'}

也就是我重新修改了p的指向不会改变外部的p的指向,从这个角度上来说确实是内部p的指向的改变没有影响外部的p的指向。这个是不是很像c++里面指针传递的过程呢,改变了函数内改变了指针的指向,但是函数外的指针指向不会发生变化。

原因解释:

每一个函数调用栈都会存储在函数调用过程中产生的数据(比如没有常量池的基本类型,或者堆里的引用,或者常量池里面的引用),那么每次调用函数过程会开辟新的函数调用栈,这个栈地址和原来函数的调用地址必然是不同的。以上面的代码为例,main的栈里面的p自然和personCrossTest里面的p所在的位置自然不同(因为栈都不同),但是里面的地址一开始是相同的,指向堆内同一个person对象,在personCrossTest函数内部改变p的指向相当于改变了personCrossTest的p的值,使personCrossTest 栈的p指向了一个新的person对象,而在main的栈里面的p没有改变值自然是没有改变对象。

总结:

1、传递的数据是什么?我个人认为是调用栈给被调用栈传递了一个对象的地址,如果对象为基本类型,则可能是要自己开辟。

2、从堆对象的角度来说传递的是堆内对象的一个地址(或者说引用)。

3、从栈的变量的角度来说传递的是调用栈的地址的复制,也就是地址的值传递。

以上是我个人的理解,希望大家和我纠正和讨论。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值