变量赋值:
对于基本数据类型变量:即int, short, long, byte, float, double, boolean, char类型的变量。这种类型变量在内存中直接存放数据。变量之间赋值如int a=b;直接传数据。a++,不影响b的数据。
对象变量:对象变量在内存中存放的是引用。这个引用值指向堆中的对象。Object c=b;传的是引用值,他们指向同一个堆对象。
如上图,age是int变量,具体数据值如9,就放在那里,而owner是对象变量,它放的是引用,指向堆里owner对象。
下两图是方法调用时在栈帧里的局部变量表里的变量和参数,图示示例了两种引用对象的方式。
此图示例了通过句柄池引用方式指向堆对象的方式。
此图示例了直接指向堆中对象的方式。
两种方式各有优势,第一种方式在对象被GC迁移时只需改变句柄池中的实例指针即可,而不用改变reference引用本身的值。第二种方式就是访问速度快。目前HotSpot虚拟机就采用的第二种方式。
下面用个例子来说明:
下面是个Dog类,用来测试时产生对象,进行引用传递
mName和mYear是类的实例变量
下面是传递变量测试类,其中也有变量赋值测试然后打印出来
主测试类
结果:
第1行和第2行对比:基础类型变量之间赋值传值,互相不影响;对象变量之间赋值传引用,mainDog和mainDog2指向同一个堆内的对象。mainDog2把对象名字改变后,mainDog打印出来也是改变后的名字。
第2、3、4、5行之间对比:方法参数的传递,基础型参数变量传值,和外面的基础类型实例变量互不影响。方法的对象类型参数传递时传引用,和外面的实例变量引用值相同,指向堆内同一个对象。此时堆内只有一个dog。
第5、6、7行之间对比:方法内的对象参数或对象局部变量改变引用值时,不影响外面的对象实例变量。此时方法内mainDog对象参数变量指向的堆对象和实例对象变量mainDog指向的堆对象不同。堆内曾有过2个dog。
如何 让对象变量之间赋值传值而不是引用呢?
Dog dog=new dog();
Dog dog2=dog;
如要达到dog2是个独立的堆对象,但属性要与dog一模一样;
Dog dog2=dog.clone();需要类实现clone接口;
设计模式中有个原型模式,就是clone;原型模式