Java 按值传递

Java 按值传递

首先,在JAVA中,其实只存在按值传递。
大家所说的值传递和引用传递其实只是对基本数据类型的传递和引用类型的传递进行了区分。

预备工作,创建一个Example的类作为这次的例子

下面展示基础数据类型的传递

在Example类中添加方法:

Example图

然后在main方法中添加一下代码:

main方法

那么,先来看看控制台打印出来的数据:

控制台

从上面的结果可以知道,main方法中 变量i 的值一直都是10,而在changeValue方法中的变量的值为5。

造成之中结果的原因是:

main方法中的 变量i  在初始化的时候赋值 i=10;

传入changeValue中的是: changeValue(int i=10) //从这里我们可以知道,其实这里的<变量i>与上面的变量i  不是同一个。

所以在 changeValue中修改了的i=5,所修改的只是changeValue的局部变量,对main中的 变量i  没影响。

下面,我们来看看引用类型的传递:

在Example类中添加方法:

main方法

然后在main方法中添加一下代码:

main方法

那么,先来看看控制台打印出来的数据:

控制台

从上面的结果,我们可以知道,exp.count的值在传入到changObj之后被改变了。

造成之中结果的原因是:

1.main方法中实例化Example类的对象exp;

2.因为exp.count初始化的值为10,所以before打印出了exp.count=10;

3.就像上面的基础类型传递一样,调用changObj(Example exp=main中的exp);//它们也不是同一个对象

那么问题来了,既然它们不是同一个对象,那么为何结果会和第一个例子的结果又区别呢?

原因:

在代码中的 Example exp = new Example();其实可以看成三部分。

1、在Java中,对象的实例化其实只是  new Example();//这样实例已经创建成功了,并在存在了 堆 里面;

下面用new Example()代表所创建的实例

2、等于号前面的Example exp ,其实是声明一个Example类型的变量exp;

3、exp初始化是引用上面new Example()。那么怎么引用呢?其实就是exp(指向)→实例的堆地址

如果有学过C/C++应该就知道这和指针类似。 变量exp本身存放的不是实例的内容,而是一个内存地址

     例如:创建一个实例new Examlpe(),它在堆中的初始地址是  0x012

     那么,exp存放的其实是0x012这个数据

                    而exp.count,其实是通过内存地址找到实例new Example(),再调用的是实例 new Example().count

 4、那么我们可以知道,在方法changObj中局部变量exp被赋予的其实也是 实例的堆地址,即上面的0x012.

 所以在方法中的变量exp一样回去找堆地址为0x012的实例。那么被找到的实例就显而易见了-new Example()

 5、那么我们修改exp.count=120,其实就是修改new Example().count=120

 因为修改的是new Example().count,本体被修改了。所以在main方法中的打印结果也跟着改变。

下面,我们来看看字符串的传递:

PS: String 类型不是基础数据类型,而是引用类型

在Example类中添加方法:

main方法

然后在main方法中添加一下代码:

main方法

那么,先来看看控制台打印出来的数据:

控制台

从上面的结果,我们可以知道main方法中的str也是没有被changStr方法修改的。

造成之中结果的原因是:

String 其实是引用类型,我们可以把它看成一个实例,而new String("Hello")才是本体,

它所做的事情就是:创建一个堆空间,并将"Hello"存放到这个堆空间中。而

前面的String str只不过是一个引用。

而作为String作为一种特殊的引用类型,str="java"本质其实是str=new String("java");

那么在方法changStr中的<局部变量str>所引用的地址已经改为了new String("java")的堆地址,

已经与main方法中的new String("Hello")没有关联,不会去影响main中的变量str。

其实通过这个例子也可以看出,如果引用类型在传入方法后,改变了引用的本体,那么接下来的操作将不再与main方法

中的变量关联。

例如在例子2中加入:

main方法

在main中重新写入代码:

main方法

可以看到控制台的结果是:

控制台

可以看到,main中的值还是10,没有发生改变。

其实大体流程可以写成这样:

1、main: Example exp = new Example();//第一个实例,例如内存地址为0x012

2、main :exp.count=10;

3、main: changObj_2(Example exp = 变量exp)

4、changObj_2: <局部变量exp> =new Example(); //第二个实例,内存地址为0x022

5、 <局部变量exp>.count=120;

上面的流程说明了,其实步骤5的修改是对于第二个实例的,所以第一个实例没有变化

最后,我们来看看一个数组的例子

main方法

main方法中的代码:

main方法

结果:

控制台

可以看出exp.chars的‘a’被替换成了’A’;

其实,这里主要就只需要理解:

在changeChar方法中changeChar(char [] chars =mian中的变量chars)

<局部变量chars>其实只是一个引用,

本体还是new Example().chars,第一个数据 chars[0]修改成’A’.这里是基础数据类型的修改。

所以后面main方法中的打印数据也改变了。

下面是这次例子的所有代码:

public class Example{
    /**
     *添加成员变量count,并赋值10
    **/
    private int count=10;


    /**
     *添加成员变量char数组类型chars,并赋值
    **/
    private char [] chars ={'a','b','c'};

    public void changeValue(int i){
        i=5;
        System.out.println("changeValue: i="+i);
    }


    public static void main(String[] args){
        Example exp =new Example();
        /**
         *基础数据类型测试
        **/
        int i=10;
        System.out.println("基础数据类型传递例子 \nbefore-> i="+i);
        exp.changeValue(i);
        System.out.println("end-> i="+i);


        System.out.println("-----------------------------------------");

        /**
         *字符串数据类型测试
        **/
        String str =new String("Hello");
        System.out.println("字符串传递例子 \nbefore-> str:"+str);
        exp.changStr(str);
        System.out.println("end-> str="+str);

        System.out.println("-----------------------------------------");
        /**
         *引用类型测试

        System.out.println("引用类型传递例子 \nbefore-> exp.count="+exp.count);
        exp.changObj(exp);
        System.out.println("end-> exp.count="+exp.count);
        System.out.println("-----------------------------------------");
        **/
        /**
         *引用类型测试2
        **/
        System.out.println("引用类型传递例子2 \nbefore-> exp.count="+exp.count);
        exp.changObj_2(exp);
        System.out.println("end-> exp.count="+exp.count);
        System.out.println("-----------------------------------------");


        /**
         *char数组例子
        **/
        System.out.print("char数组例子 \nbefore-> exp.chars=");
        System.out.println(exp.chars);
        exp.changeChar(exp.chars);
        System.out.print("end-> exp.chars=");
        System.out.println(exp.chars);
        System.out.println("-----------------------------------------");
    }


    private void changeChar(char []  chars){
        chars[0] ='A';
        System.out.print("changeChar: chars=");
        System.out.println(chars);
    }

    public void changStr(String str){
        str="java";

        System.out.println("changStr: str="+str);
    }


    /**
     *直接传入对象,对对象的成员变量进行修改;
     **/
    public void changObj(Example exp){
        exp.count=120;
        System.out.println("changObj: exp.count="+exp.count);
    }

    /**
     *在方法中重新实例化一个对象
    **/
    public void changObj_2(Example exp){
        exp = new Example();
        exp.count=120;
        System.out.println("changObj: exp.count="+exp.count);
    }

}

如果CSDN的图片没有权限访问,可以点击此处直接访问CSDN的文章

END

– Nowy

– 2015.12.10

分享到