一.基本类型与引用类型的值
在计算机高级语言变量中包含两种不同数据类型:基本类型与引用类型.基本类型指那些保存在栈内存中的简单数据段,也就是说这些变量的值完全保存在栈内存中,而引用类型值指那些保存在堆中的对象,这就是说,引用类型变量在栈中保存的只是一个指向堆中指定对象的 指针而已,为什么要这么做呢,因为对象大小不能固定,而基础类型大小是固定的,如int型就占4个字节(不同语言,平台有所差异),我们可以将固定大小的放在一个数据结构中,如果是基础类型直接取值,如果是引用类型首先从栈中读取内存地址,然后顺藤摸瓜,根据地址找到在堆中的值,这样可以提高我们的查询速度,
JAVA中的基础类型有int,char,byte,long,short,boolean,特别注意String不是基础数据类型,但在javascript中ECMAScript放弃这一传统,将String作为基础数据类型.栈堆关系如下图,一目了然:
二.复制变量值
除了保存方式不同外,基础数据类型与引用同数据类型在复制变量时也不一样,如下例所示程序:
int num1 = 5;
int num2 = num1;
num2 = 10;
System.out.println(num1); //5
System.out.println(num2); //10
初始变量num1的值等于5当将变量num1的值赋于变量num2,num2也保存了5的值,但这两个5的值是完全独立的,在num2中的5只是num1中的5的一个副本而已,相信这点大家很容易理解,下面配合图标将这次赋值过程展现出来:
对于引用变量的复制,实质上,我们复制的是栈内存中的指针,也就是复制变量的指针的副本,复制后两个变量指向同一个对象,相信这一点也不难理解,惯例图表展现:
Person p1 = new Person();
p1.setName("复制前所赋值");
Person p2 = p1;
p2.setName("复制后所赋值");
System.out.println(p2.getName());// 复制后所赋值
三.参数传递
与变量复制一样,参数传递基础类型与引用类型也存在差异,在java这门计算机语言中,非常多的书籍都会写到基础数据类型是值传递,而引用类型是引用传递,其实我赞同前半句,不过对后半句有异议,后面再谈,首先先来看看基础类型的值传递.
在向参数传递基本类型的值的时候,被传递的变量的值会复制给函数的一个局部变量,局部变量所对应的内存中会参数被传递变量值的副本,所以当我们修改局部变量时被传递变量不会发生改变:
public static int addNum(int num) {
num += 100;
return num;
}
int num = 10;
int result = addNum(num);
System.out.println("操作后的num :" + num); // 10
System.out.println("结果result :" + result); // 110
函数addNum()有一个参数num当我们使用变量num传入时,实际上是在addNum函数作用域内产生一个num局部变量,该局部变量的值是被传入参数值的副本,当我们修改局部变量时,外层变量不会发生改变,所以我们最后打印的时候外层变量仍然为10并没有受到函数参数自增100的影响。
前面已经对引用类型参数传递的一些看法,下面我们先来看一个例子:
public static void setName(Person p) {
p.setName("作为参数后的值");
}
Person p = new Person();
p.setName("作为参数前的值");
setName(p);
System.out.println(p.getName()); // 作为参数后的值
从上面例子可以看出,当我们创建一个对象后,调用函数对对象的属性进行修改,发现函数外层的对象也跟着修改了,可以看出参数p与外层对象p指向的是堆内存中的同一个对象,换句话说,这应该是一个值传递,因为前面我们已经说过,在栈内存中引用类型变量保存的是堆内存中对应对象的地址,所以参数获得了一个被传递变量的指针类型副本,下面我们再来看一个例子 :
public static void setName(Person p) {
p.setName("操作前名称");
p = new Person(); // 使参数指向新的堆地址
p.setName("操作后的名称");
}
Person p = new Person();
setName(p);
System.out.println(p.getName()); // 操作前名称
与前一个例子相比,我们在setName函数中先对参数p赋值,然后让参数p指向一个新的对象,再赋值,结果打印出来的信息是我们在使得参数P指向一个新的对象之前所做的操作,也就是说并没有修改原被传递参数的指针信息,所以同样为值传递(javascript也是一样的)。