java引用传递和值传递

Python047

java引用传递和值传递,第1张

结果是(p1[0,0], p2[5,5])就对了, 下图是执行流程以及内存变化

记住: 当对象的引用被执行赋值操作(=)后, 讲不在指向原来的对象(新的对象不是原来的对象)

// modify方法做如下修改就知道为什么是那样的结果了:

    private static void modify(Point p1,Point p2){

        System.out.println(p2) // 注意观察hashcode值, 不要重写toString()方法

        Point p = p1

        p1 = p2

        p2 = p

        p1.setLocation(5, 5)

        p2 = new Point(5, 5)

        System.out.println(p2) // 这里p2与之前的p2的hashcode值已经不是同一份

    }

    

// 修改main方法如下

    public static void main(String[] args)

    {

        Point p1 = new Point(0,0)

        Point p2 = new Point(0,0)

        System.out.println(p2)

        modify(p1, p2)

        System.out.println(p2)    // modify执行完成后, p2的指向并未改变

        System.out.println(p1.getX()+","+p1.getY()+","+p2.getX()+","+p2.getY())

    }

    

    /**

    * 可以使用断点调试观察modify方法中p2的指向变化

    * Eclipse中引用被赋予新的值时, 调试界面中[变量列表]的变化为 黄色高亮显示

    */

希望对你有帮助!

Java中的参数传递:分为值传递和引用传递

但本质上,Java中只有值传递。引用传递,其实可以理解为传的是类似指针的东西。

值传递就是把基本变量的值拷贝一份,传递这个拷贝。引用传递则是传递的引用的地址,也就是该变量在内存空间的地址。

1.值传递

只有基本数据类型采用值传递,特点是传递的是值的拷贝,传递完后两者就没有关系了。也就是说方法内和方法外的值互不相干

基本数据类型:

·整型:int,long,byte,short

浮点型:float,double

字符型:char

布尔型:boolean

注:8种基本数据类型以外的数据类型都为引用类型。

2.引用传递

指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。

传递的是一个拷贝,即副本。也就是说,对于一个参数传递,存在两个地址指向同一个内存空间。这里我们可以用内存分配示意图来体现

3.String类型传递

先说结论,String类型传递与基本数据类型的传递效果相似。

说明:

String类对象一旦创建,其内容不可更改:

String类的所有方法都不会改变String类对象内容,要改变String类对象的值就必须创建一个新的String对象。

也就是说,当进行参数传递时,如果方法内对String类对象的值进行了修改,那么实际上是创建了一个新的String类对象,然后让原来的变量指向它而已。但是这个“原来的变量”是一份拷贝副本,只是一开始创建的时候与主方法中的传递的值相同而已,现在改变之后,两者就毫无关系了。

你是c/c++或是vb转过来的吗?在java中过多考虑引用(指针)和值之间的关系是步入歧途,这正是java的设计者极力避免你考虑的问题。

你需要明白的是:

1、java中所有方法的参数的传递都是“值传递”;

2、java中所有对象类型的变量的“值”,本质上说,包含了java堆中的实际对象的地址,你可以大体认为java的变量对应了c/c++中的指针(其实这里面有更复杂的机制)。事实上,java并不像c/c++一样明确的区分“值语义”与“引用语义”,java栈中也不会存放任何对象的实体(这点与c/c++不同,c/c++栈中可以存放对象实体),所有的java对象都是在堆中。

概念上的区别在于,我这里提到的“变量”是指java栈中的内容,对应你说的“引用”;我提到的“对象”是指java堆中的实体,对应你说的“值”。而一般java教材中提到的“值传递”,是指这些“变量”的内容的传递,不是java堆中的对象实体的传递。

你用字符串来做实验,并推广为所有java对象的做法,并不是特别合适。java的string类型有特殊的处理:所有编译期认识的字符串,都会被放到常量池,于是下面的语句:

a

=

"s"

b

=

"s"

a和b并不像其它对象一样有创建的动作,都是直接指向常量池中的"s",所以你可以得到a==b。而下面的语句:

a

=

new

string("s")

b

=

new

string("s")

是分别在java堆中创建了2个对象,此时a!=b。

本质上说,对于基本数据类型(整数、字符等),java的符号==,用于判断二者的值是否相等;对于对象类型,java的符号==,用于判断两个变量是否是“同一个对象”,equals()方法才是用于判断两个对象是否相等。

你希望实现的swap逻辑,在java中通常认为是无法实现的。拿你这个例子来说,swapvalue()中的tmpvalue无论怎么更改,只是改变tmpvalue自己的内容(即不断指向不同的对象),并不会改变value中的内容(始终指向同一个对象)。这也是为什么java最初说自己永远是值传递。你只有改变tmpvalue指向的对象的值(通过调用这个对象的方法或是更改它的属性),使用value访问时,才能看到这些改变。

为了弥补这个缺陷,c#才加入了ref关键字,允许传入变量的引用(如果参考c/c++,c#传递的实际是二级指针,它的内容是栈中的变量的地址)。