此内容摘自《Thinking in java》Page39.
赋值使用操作符“=”。它的意思是“取右边的值(即右值),把它[b][color=red]复制[/color][/b]给左边(即左值)”。右值可以是任何常数、变量或者表达式(只要它能生成一个值就行)。但是左值必须是一个明确的、已命名的变量。也就是说,必须有一个物理空间可以存储等号右边的值。举例来说,可将一个常数赋给一个变量:
a = 4;
但是不能把任何东西赋给一个常数,常数不能作为左值(比如不能4=a;)。
对基本数据类型的赋值是很简单的。基本类型存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容[b][color=blue]复制[/color][/b]到了另一个地方。例如,对基本数据类型使用a=b,那么b的内容就赋值给a。若接着又修改了a,而b根本不会受这种修改的影响。作为程序员,这正是大多数情况下我们希望看到的。
但是在为对象“赋值”的时候,情况却发生了变化。对一个对象进行操作时,我们真正操作的是对对象的引用。所以倘若“将一个对象赋值给另一个对象”,实际是将“引用”从一个地方[b][color=blue]复制[/color][/b]到另一个地方。这意味着假若对对象使用c=d,那么c和d都指向原本只有d指向的那个对象(如果c此前包含的对对象的引用是指向另一个对象,那么在执行c=d赋值的时候,这个引用被覆盖,也就是丢失了;而那个不再被引用的对象将被“垃圾回收器”自动清理(注意条件:不可达时才会被清理))。由于赋值操作的是一个对象的引用,所以此时修改c的时候也就相当于修改了d!这是由于c和d包含的是相同的引用,它们指向相同的对象。
这种特殊的现象通常被称作“[b]别名现象[/b]”,是java操作对象的一种基本方式。
[b]方法调用中的别名问题[/b]
将一个对象传递给方法时,也会产生别名问题:
在许多的编程语言中,方法f()似乎要在它的作用域内复制其参数Letter y的一个副本;但实际上只是传递了一个引用。所以代码行y.c = 'z';实际改变的是f()之外的对象。
------------------------------------------------------------
[b][color=green]堆栈[/color][/b]:对象的引用、基本类型的变量(这个变量直接存储值),存储在堆栈中。堆栈位于通用RAM(随机存取存储器)中。
[b][color=green]堆[/color][/b]:一种通用的内存池,也位于RAM中,用于存放所有的java对象。
常量存储:常量值通常直接存放在程序代码内部,这种存储区的一个例子是字符串池。所有的字面常量字符串和具有字符串值的常量表达式都自动是内存限定的,并且会置于特殊的静态存储区中,比如ROM(只读存储器)。
------------------------------------------------------------
java中的引用与javascript中的引用是一样的,都分为基本类型数据与引用类型数据:
[b]基本类型数据[/b]:
例如:obj = 3;
ref = obj;
此时,是拷贝一份obj的值给ref,拷贝完成后,ref与obj之间就没有任何关系了。
[b]引用类型数据[/b]:javascript引用与java引用一样,都是指向最终的对象(位于堆区),而非指向引用本身(堆栈区)
例如obj是一个对象: obj = new Obj(); //在js中,obj = {a:1,b:2}
ref = obj;
此时,ref与obj所指向的对象是同一个,改变它们俩中的任意一个,另一个也会跟着改变;
如果obj再指向其他对象,这时就跟ref没有关系了,ref还指向开始的那个对象(类似的,如果ref指向其它对象,那么ref跟obj就没有关系了,它们分别指向不同的对象了);下面是一个js中引用的例子:
[b][color=red]同一个方法中[/color][/b]:
ref = obj
基本类型数据: 拷贝一份给ref
引用类型数据: ref 与 obj指向同一个对象,改变她们俩个的任意一个,另一个也会跟着改变; 如果其中一个又指向了其它对象时,那么跟另一个就没有关系了,另一个还指向原来的那个对象。
[b][color=red]当做参数传递到另一个方法中[/color][/b]:
[b]传值---传递基本数据类型参数[/b]
[b]引用传递---对象作为参数[/b]
1. 基本类型和基本类型变量被当作参数传递给方法时,是值传递。在方法实体中,无法给原变量重新赋值,也无法改变它的值。 例如,int,float,Integer,String等
2. 对象和引用型变量被当作参数传递给方法时,是引用传递。在方法实体中,无法给原变量重新赋值,但是可以改变它所指向对象的属性。
赋值使用操作符“=”。它的意思是“取右边的值(即右值),把它[b][color=red]复制[/color][/b]给左边(即左值)”。右值可以是任何常数、变量或者表达式(只要它能生成一个值就行)。但是左值必须是一个明确的、已命名的变量。也就是说,必须有一个物理空间可以存储等号右边的值。举例来说,可将一个常数赋给一个变量:
a = 4;
但是不能把任何东西赋给一个常数,常数不能作为左值(比如不能4=a;)。
对基本数据类型的赋值是很简单的。基本类型存储了实际的数值,而并非指向一个对象的引用,所以在为其赋值的时候,是直接将一个地方的内容[b][color=blue]复制[/color][/b]到了另一个地方。例如,对基本数据类型使用a=b,那么b的内容就赋值给a。若接着又修改了a,而b根本不会受这种修改的影响。作为程序员,这正是大多数情况下我们希望看到的。
但是在为对象“赋值”的时候,情况却发生了变化。对一个对象进行操作时,我们真正操作的是对对象的引用。所以倘若“将一个对象赋值给另一个对象”,实际是将“引用”从一个地方[b][color=blue]复制[/color][/b]到另一个地方。这意味着假若对对象使用c=d,那么c和d都指向原本只有d指向的那个对象(如果c此前包含的对对象的引用是指向另一个对象,那么在执行c=d赋值的时候,这个引用被覆盖,也就是丢失了;而那个不再被引用的对象将被“垃圾回收器”自动清理(注意条件:不可达时才会被清理))。由于赋值操作的是一个对象的引用,所以此时修改c的时候也就相当于修改了d!这是由于c和d包含的是相同的引用,它们指向相同的对象。
这种特殊的现象通常被称作“[b]别名现象[/b]”,是java操作对象的一种基本方式。
[b]方法调用中的别名问题[/b]
将一个对象传递给方法时,也会产生别名问题:
class Letter{
char c;
}
public class PassObject{
static void f(Letter y){
y.c = 'z';
}
public static void main(String[] args){
Letter x = new Letter();
x.c = 'a';
print(x.c); //打印a
f(x);
print(x.c); //打印z
}
}
在许多的编程语言中,方法f()似乎要在它的作用域内复制其参数Letter y的一个副本;但实际上只是传递了一个引用。所以代码行y.c = 'z';实际改变的是f()之外的对象。
------------------------------------------------------------
[b][color=green]堆栈[/color][/b]:对象的引用、基本类型的变量(这个变量直接存储值),存储在堆栈中。堆栈位于通用RAM(随机存取存储器)中。
[b][color=green]堆[/color][/b]:一种通用的内存池,也位于RAM中,用于存放所有的java对象。
常量存储:常量值通常直接存放在程序代码内部,这种存储区的一个例子是字符串池。所有的字面常量字符串和具有字符串值的常量表达式都自动是内存限定的,并且会置于特殊的静态存储区中,比如ROM(只读存储器)。
------------------------------------------------------------
java中的引用与javascript中的引用是一样的,都分为基本类型数据与引用类型数据:
[b]基本类型数据[/b]:
例如:obj = 3;
ref = obj;
此时,是拷贝一份obj的值给ref,拷贝完成后,ref与obj之间就没有任何关系了。
[b]引用类型数据[/b]:javascript引用与java引用一样,都是指向最终的对象(位于堆区),而非指向引用本身(堆栈区)
例如obj是一个对象: obj = new Obj(); //在js中,obj = {a:1,b:2}
ref = obj;
此时,ref与obj所指向的对象是同一个,改变它们俩中的任意一个,另一个也会跟着改变;
如果obj再指向其他对象,这时就跟ref没有关系了,ref还指向开始的那个对象(类似的,如果ref指向其它对象,那么ref跟obj就没有关系了,它们分别指向不同的对象了);下面是一个js中引用的例子:
var obj = {}; // 空对象
var ref = obj; // 引用
obj.name = "objectA" ;
alert(ref.name); //ref跟着添加了name属性 打印objectA
obj = ["one", "two", "three"]; //obj指向了另一个对象(数组对象)
alert(ref.name); //ref还指向原来的对象 打印objectA
alert(obj.length ); //打印3
alert(ref.length); //打印undefined
obj只是对一个匿名对象的引用,所以,ref并非指向它,当obj指向另一个数组对象时,可以看到,引用ref并未改变,而始终指向这那个后来添加了name属性的"空"对象"{}"
[b][color=red]同一个方法中[/color][/b]:
ref = obj
基本类型数据: 拷贝一份给ref
引用类型数据: ref 与 obj指向同一个对象,改变她们俩个的任意一个,另一个也会跟着改变; 如果其中一个又指向了其它对象时,那么跟另一个就没有关系了,另一个还指向原来的那个对象。
[b][color=red]当做参数传递到另一个方法中[/color][/b]:
[b]传值---传递基本数据类型参数[/b]
[b]引用传递---对象作为参数[/b]
1. 基本类型和基本类型变量被当作参数传递给方法时,是值传递。在方法实体中,无法给原变量重新赋值,也无法改变它的值。 例如,int,float,Integer,String等
2. 对象和引用型变量被当作参数传递给方法时,是引用传递。在方法实体中,无法给原变量重新赋值,但是可以改变它所指向对象的属性。