(一)Java
JVM的重要知识:
(1)栈空间(Stack),连续的存储空间,遵循后进先出的原则,用于存放局部变量。
(2)堆空间(Heap),该区域是线程共享的,不连续的空间,用于存放对象实例。垃圾回收器最主要针对的对象,对这部分的回收效率影响了VM的整体性能。
(3)方法区(Method Area),该区域是所有线程共享的,主要用于存放类的信息,常量、静态变量、即时编译器编译后的代码等。垃圾回收器对这块区域的回收主要是针对常量池和类的卸载。
Java中除了基本数据类型,其他的均是引用类型,包括类、数组等等。
- 值传递
参数是基本类型(byte,short,int,long,float,double,char,boolean),传递的是基本类型的字面量值的拷贝。
private void swapValue(int num1, int num2){
int temp;
temp = num1;
num1 = num2;
num2 = temp;
}
//调用
int a = 1,b=2;
swapValue (a,b);
System.out.println (a +","+b);//1,2 并不会调换顺序
图解:
a,b在内存中的值并未改变,堆中的num1,num2发生交换。
- 引用传递
参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝。
private void changeStr(StringBuffer stringBuffer){
stringBuffer.append (",yes");
}
//测试代码
void test(){
StringBuffer stra=new StringBuffer ("1");
changeStr (stra);
System.out.println (stra);//1,yes 引用类型因为是传递地址,因此修改了堆内存的同一对象
}
图解:
由于是引用传递,stra和stringBuffer同指堆内存中的一块区域,修改stringBuffer,即是修改stra。
引用传递的特殊情况:
private void changeString(String str){
str = "2";
}
//测试代码
void test(){
String strInit="1";
changeString (strInit);
System.out.println (strInit);//1 String是引用类型,传递的是地址,但是并未发生改变
}
图解:
原先形式入参str与strInit指向同一片堆内存区域,之后str="2"将str的内存指向另一块堆内存导致上述结果的特殊。
(二)Javascript
- 值传递
var a = 2;
var b = a; // b是a的值的一个副本
b++;
a; // 2
b; // 3
- 引用传递
var c = [1,2,3];
var d = c; // d是[1,2,3]的一个引用,同指一块内存区域
d.push( 4 );
d; // [1,2,3,4]
c; // [1,2,3,4] 修改同指的那片内存区域,因此c也跟着变化了
d = [4,5,6];//[4,5,6]
console.log(c);//[1,2,3,4] d指向一片新的内存区域[4,5,6],不会改变c的指向,因此c还是[1,2,3,4]
引用副本传递:
function foo(x) {
x.push( 4 );
x; // [1,2,3,4]
// 然后
x.length = 0; // 清空数组
x.push( 4, 5, 6, 7 );
x; // [4,5,6,7]
}
var a = [1,2,3];
foo( a );
a; // 是[4,5,6,7],不是[1,2,3,4]
a=[1,2,3,4];
foo( a.slice() );//a.slice()传入的是a的浅复制副本,因此不会改变a的那块内存区域
a;//还是[1,2,3,4]
foo(a);
a;//[4,5,6,7]