对于Java的值传递和引用传递的区别

我知道有人会说,Java只有值传递而没有引用传递,但是如果把引用地址也看成一个值的话,是可以这么说的。
对于两个传递的定义是什么呢?
第一,值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量。(一般发生在基本数据类型当中)
第二,引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。 所以对该副本进行操作时,会同时改变原对象。(发生在引用类型当中)
很多时候,传递都是发生在往方法里传参的情况,这个时候,你是可以将方法的形参当成一个变量,实际上,形参就是局部变量。
我会根据几道例题,来说明他们之间的区别

这是一道面试题

public static void main(String[] args) {  
    MyClass myClass = new MyClass();  
    change(myClass);  
    System.out.println(myClass.val);  
}  

private static void change(MyClass myClass) {  
        myClass = new MyClass();  
    myClass.val = 2;  
}  
public static class MyClass{  
    int val = 1;  
}  

为了方便理解,画图时,形参我改为myClass2了
这里写图片描述
以上可以大致可以清楚的看见引用变量指向对象的改变,但是为什么注释掉第三步会影响结果?
看下图
这里写图片描述
一开始的第三步的作用是,重写new一个对象,所以myClass2被重新赋值地址值,并不是原来myClass传给它的对象地址值。
可以看见,因为没有了第三步,所以这两个引用都是指向同一堆上的对象,所以任意一个引用只要对该对象进行数据域的操作,都会影响到数据域的改变。

myClass.val=2;      //重新对变量val赋值

这便是引用传递。

再来看一道引用传递的面试题。
以下代码结果是什么?

  public class foo {

   public static void main(String sgf[]) {

   StringBuffer a=new StringBuffer(“A”);

   StringBuffer b=new StringBuffer(“B”);

   operate(a,b);

   System.out.println(a+”.”+b);

   }

   static void operate(StringBuffer x,StringBuffer y) {

   x.append(y);

   y=x;
   }
  }

看一下图
这里写图片描述

还是我刚才的那句话,你把形参看作是一个引用变量,引用传参的实际就是地址值的赋值。

  x.append(y);

上面这个操作对应着是第二步骤,是对同一个对象的数据域的操作。

 y=x;

这是再一次的引用传递,将x的地址赋值给了y,导致原来 y 放弃指向了 B字符 所在对象,而指向了 AB字符 所在的对象。
注意,很多新手误以为,x=y 就是b=a,这是编程,不是数学。
这里只是将 x 的地址赋值给了 y,与 b=a 没有一毛钱的关系, ba 的存储的地址未发生改变。

再来看一道值传递的例题

public static void change(int i, int j) {    
      int temp = i;    
      i =j;    
      j =temp;   
}    

public static void main(String[] args) {    
      int a = 3;    
      int b = 4;    
      change(a,b);    
      System.out.println(a);    
      System.out.println(b);   
}    

change方法是平常将数值互换的一种方法,但是前提必须是本值,而不是传递的值。
在main方法中调用了change方法,在将a和b的值传递过去,这时就要注意了,这是值传递,传递的只是一个副本,与原值无关。
也就是,无论change方法中如何操作这两个形参a和b,输出的始终是

3
4

到这里,其实还没有结束,因为,你要注意有一个特殊的数据类型,就是String。
先来说String到底特殊在那一方面:
第一,当new出新对象时,会产生两个对象,第一是在字符串常量区,第二是在堆上(new 出对象)
第二,String是不可改变的,任何试图改变String的行为都会产生新对象,所以无论是用”+”还是用toLowerCase()等方法,都会产生新对象。
第三,String是引用类型。
虽然我说的有一丁点的偏题,但这些是对String传递时前的铺垫。

进入正题,看下面这道题,会输出什么?

public static void change(String s) {     
    s = “123”;    
}     

public static void main(String args[]) {     
    String s = “abc”;     
    change(s);     
    System.out.println(s);  
}  

看下面的图

这里写图片描述

为什么第二步和第三步会不一样?
String不是引用吗?
引用传递不是说,操作对象的数据域应该会影响到指向同一对象的引用啊?

但是,看我上面说的第二句话,String是不可改变的,任何试图改变String的行为都会产生新对象。
所以,实际上到第三步,两个S的指向已经是不同对象了,并没有给S重新赋值为“ 123”

再来看一题,

public class Example {    
    String str = "abc";    
    char[] ch = { 'a', 'b', 'c' };    
    public static void main(String args[]) {    
        Example ex = new Example();    
        ex.change(ex.str, ex.ch);    
        System.out.println(ex.str);    
        System.out.println(ex.ch);    
    }    
    public void change(String str, char ch[]) {  
   *** //  ch = new char[]{'a','b','c'};    
        str = "change";    
        ch[0] = 'c';    
    }    
}  

输出的结果为:

abc
cba

str变量不用说,是上面一道题一样的,两个str,
形参 str 指向了”change”,
成员变量 str 指向了”abc”。
变量ch和引用传递是一样的,都是操作的为同一对象,如果有* * *的一行不注释的话,结果就为

abc
abc

因为change的形参变量ch被重新赋值了地址值()。

ch = new char[]{'a','b','c'};

它操作的不再是成员变量 char[] ch 指向的对象了。

笔者水平有限,如有缺点和不足,请各位指出,谢谢大家。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值