Java call by value 和 by reference (值传递和引用传递)

关于JAVA中参数传递问题有两种,一种是按值传递(如果是基本类型),另一种是按引用传递(如果是對象).

首先以两个例子开始:

package com.whf.ByValue_ByReference;
/** 
 * @author :辰
 * E-mail: 15538323378@163.com 
 * 创建时间:2017-3-24 上午8:37:04 
 *  
 */


public class Test {
    public static void main(String[] args) {
        StringBuffer a = new StringBuffer("A");
        StringBuffer b = new StringBuffer("B");
        operate(a,b);
        System.out.println(a+","+b);//AB,B
    }
    static void operate(StringBuffer x,StringBuffer y){
        x.append(y);
        y=x;
    }

}

输出:AB,B
Test2

package com.whf.ByValue_ByReference;
/** 
 * @author :辰
 * E-mail: 15538323378@163.com 
 * 创建时间:2017-3-24 上午8:42:09 
 *  
 */
public class Test2 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        Integer i = new Integer(0);
        add3(i);
        System.out.println(i.intValue());//0

    }

    private static void add3(Integer i) {
        // TODO Auto-generated method stub
        int val = i.intValue();
        val += 3;
        i = new Integer(val);
    }

}

输出:0

首先我们应该明白JAVA中的参数传递全是以值传递的。是基本类型,就拷贝一个基本类型传进方法;是引用,就拷贝一个引用变量传进去方法,理解了这 两点就能理解方法操作对象的相关问题了。最好能画出引用指向对象的图出来,就能完全理解了。
第1题,调用operate方法时,传入了两个引用a,b的拷贝x,y,这两个x,y都指向原a,b引用所指向的对象。x.append(y)对它指向的 对象(即a指向的对象)进行了操作。而x=y,只是两个拷贝变量在赋值,并没有影响到原b所指向的对象。所以b所指向的对象仍然为B。
第2题,i=new Integer(val)只是一个引用的拷贝指向了另外一个对象,而原来的i仍然是指向对象new Integer(0)的。
把握住了JAVA都是传值并且传的都是拷贝的话,类似的题大家都能迎刃而解了。

Java中的参数传递只有一种方式: by value. 理论说教太麻烦了,直接看些例子吧:
1). 基本类型

package com.whf.ByValue_ByReference;
/** 
 * @author :辰
 * E-mail: 15538323378@163.com 
 * 创建时间:2017-3-24 上午8:46:11 
 *  
 */
public class Test3 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int x = 1;
        System.out.println(x);//1
        test(x);
        System.out.println(x);//1-------->by value


    }

    private static void test(int x) {
        // TODO Auto-generated method stub
        x = 2;

    }

}

2). 引用类型

package com.whf.ByValue_ByReference;
/** 
 * @author :辰
 * E-mail: 15538323378@163.com 
 * 创建时间:2017-3-24 上午8:48:00 
 *  
 */
public class Test4 {
    public static void main(String[] args) {
        Integer  x = new Integer(1);
        System.out.println(x);//    1
        test(x);
        System.out.println(x);//    1
    }

    private static void test(Integer x) {
        // TODO Auto-generated method stub
        x = new Integer(2);
    }

}

理解这里的关键是区分对象和引用。 这里声明的x是一个引用,而不是一个对象(只是Java把它设计为看上去好像是对象一样)。这个引用它指向了一个对象,这个对象就是后面用new关键字生 成的对象。因此,可以说x指向了一个Integer对象。
在调用test方法的时候,程序将x作为参数传递给test方法了。这里仍然是值传递,在test调用过程中,会产生一份新的引用(不妨叫做y)。此 时,x和y指向了同一个对象。
x和y指向的是同一个对象, 由于Java的设计,我们可以通过操作引用来达到操作对象的目的。因此,如果我们此时使用y来修改对象的属性 (例如,y.someField++); 你可以看到x指向的对象同时也被修改到了。
另一方面,如果我们让y指向另外一个对象, y=new Integer(2); 此时x和y就指向了不同的
对象。y修改了它指向的对象的属性,很显然不会影响到x指向的对象。

有人说了数组。数组也是一个引用类型,它的参数传递方式按照引用类型的参数传递一样可以解释得通:

package com.whf.ByValue_ByReference;

import java.util.Arrays;

/** 
 * @author :辰
 * E-mail: 15538323378@163.com 
 * 创建时间:2017-3-24 上午8:50:06 
 *  
 */
public class Test5 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int[] aa = {3,2,1};
        System.out.println(Arrays.toString(aa));//[3, 2, 1]
        test(aa);
        System.out.println(Arrays.toString(aa));//[3, 2, 1]
        test2(aa);
        System.out.println(Arrays.toString(aa));//[4, 2, 1]
    }
     static void test2(int[] aa) {
        // TODO Auto-generated method stub
        if (aa!=null && aa.length>0) {
            aa[0]++;    //修改原来对象
        }
    }
    static void test(int[] a){
        a = new int[]{11,12,13};//  指向了新对象
    }

}

对象是传引用(call by reference),简单类型是传值(call by value),不要被网上的一些概念所迷惑!!!你可以自己做个试验。
至于String等类型传的还是引用。如果你用concat方法,String对象的原值就会被改变。
但你如果按如下方法:

package com.whf.ByValue_ByReference;
/** 
 * @author :辰
 * E-mail: 15538323378@163.com 
 * 创建时间:2017-3-24 上午9:02:01 
 *  
 */
public class Test6 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String str = "Hello";
        test(str);
        System.out.println(str);    //Hello

    }

    private static void test(String str) {
        // TODO Auto-generated method stub
        str = "World";
    }

}

  运行结果:Hello
这里str = “World” 就等同于 String str=new String(“World”)。所以结果没有改变!!!
下列程序在1处是否会有异常,如果没有,输出是什么?是否会运行到2处,如果会,输出是什么?为什么会有这样的结果?

package com.whf.ByValue_ByReference;

import java.util.ArrayList;
import java.util.List;

/** 
 * @author :辰
 * E-mail: 15538323378@163.com 
 * 创建时间:2017-3-24 上午9:04:11 
 *  
 */
public class Test7 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        List list = new ArrayList();
        test2(list);
        System.out.println(list.size());//1处    (输出0)
        test3(list);
        System.out.println(list.size());//2处    (输出1)

    }

    private static void test3(List list) {
        // TODO Auto-generated method stub
        list.add("aaaaa");
    }

    private static void test2(List list) {
        // TODO Auto-generated method stub
        list = null;
    }

}

plumechen:

不会出错的。结果是0,1。

因为test2(list)传得是list的引用,我理解成指针置的副本,list=null;只是把那个传入的值设置为null,不改变原来 list的指针和内容。test3(list)传入的一样,但是执行了list.add()由于传入指针值的副本也指向原来的那个list的地址,所以原 来的那个list的内容就改变了,size变成了1了

 6.下列正确的有()

  A. call by value不会改变实际参数的数值

  B. call by reference能改变实际参数的参考地址

  C. call by reference不能改变实际参数的参考地址

  D. call by reference能改变实际参数的内容

  答案:ACD

Java中的参数传递只有一种方式: 值传递 (by value)

1、简单类型类型,在调用的方法中,直接是实参的一个拷贝

2、对象:程序将对象x作为参数传递给方法了。这里仍然是值传递,在方法调用过程中,会产生一份新的引用(不妨叫做y)。此时,x和y指向了同一个对象。

我们可以通过操作引用来达到操作对象的目的。 因此,如果我们此时使用y来修改对象的属性 (例如,y.someField++); 你可以看到x指向的对象同时也被修改到了。(值传递,在方法里产生引用,操作引用达到操作对象。所以引用可以修改实参(对象)的内容)
实验

package callbyvalue;

//public class Test2 {
//
//    public static void main (String [] args) {
//    StringBuffer a = new StringBuffer ("A");
//    StringBuffer b = new StringBuffer ("B");
//    operate (a,b);
//    System.out.println(a+","+b);          //AB,B
//    }
//
//    static void operate(StringBuffer x, StringBuffer y){  //JAVA中的参数传递全是以值传递的。
//        //是基本类型,就拷贝一个基本类型传进方法;是引用,就拷贝一个引用变量传进去方法
//         x.append(y);  //x.append(y)对它指向的对象(即a指向的对象)进行了操作
//         y = x;    //只是两个拷贝变量在赋值      并不会影响原来的对象
//         System.out.println(y);    //AB
//       }
//    }


//public class Test2 {
//
//    public static void add3 (Integer i){
//          int val=i.intValue();
//          val += 3;
//          i = new Integer (val);  //只是一个引用的拷贝指向了另外一个对象,而原来的i仍然是指向对象new Integer(0)的
//    }
//
//    public static void main (String args [ ] ) {
//    Integer i = new Integer (0);
//    add3 (i);
//    System.out.println (i.intValue ( ));  //0
//    }
//    }

我的实验

//public class Test2 {  //我的实验
//
//    public static void change (int i){
//        i=6;           //给拷贝赋值,并没有改变a指向的值
//    }
//
//    public static void main (String args [ ] ) {
//    int a=5;
//    change(a);
//      System.out.println (a);  //5   JAVA都是传值并且传的都是拷贝的话
//    }
//    }


//public class Test2 {  //我的实验
//
//    public static void change (int i){
//        i++;           //对象是传引用(call by reference),简单类型是传值(call by value)
//                       //传值(call by value)不会改变实际参数的数值
//    }
//
//    public static void main (String args [ ] ) {
//    int a=5;
//    change(a);
//      System.out.println (a);  //5  
//    }
//    }

Test8

package com.whf.ByValue_ByReference;
/** 
 * @author :辰
 * E-mail: 15538323378@163.com 
 * 创建时间:2017-3-24 上午9:17:16 
 *  
 */
public class Test8 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        int a = 8;
        change(a);
        System.out.println(a);//8


        int x = 5;
        change1(x);
        System.out.println(x);//5
    }

    private static void change1(int x) {
        // TODO Auto-generated method stub
        x++;
    }

    private static void change(int a) {
        // TODO Auto-generated method stub
        a =10;
    }


}

参考地址:原文链接

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值