我们都知道,Java中是没有指针的,所以Java中的引用就相对而言,比C++有指针并且分工明确,要稍微复杂一些。
Pre-值类型和对象类型(引用类型)的地址空间
图片
首先,值类型在图1中很明显,他的值直接是放在他所在的地址中的,而对象类型所对应的内存是存放一个地址,而这个地址是指向在堆中的内存地址。
其次就是他们其实都是存在栈中的,对象实例存放在堆中。
1、函数传参
首先,对于函数传参的引用,函数传参分为
- 基础类型 int,string等: 函数内的操作不会改变传入参数的本身
- 对象:会改变传入对象的属性值,但不会改变引用,对象内的对象属性也是一样的,只会被改变属性值,但是不会改变引用
public Test{
public static void main(String[] args) {
BitSet bit = new BitSet();
bit.set(0);
BitSet bit2 = new BitSet();
bit2.set(1);
int index = 0;
test(bit, index, bit2);
//对象的属性被改变了,同时也可以说明引用未被改变
System.out.println(bit.get(2));
// 基础类型未被改变
System.out.println(index);
}
public static void test(BitSet bit, int index, BitSet bit2){
// 对象内的属性会被改变
bit.set(2);
// 对象的引用不会呗改变
bit = bit2;
// 基础类型不会呗改变
index = 5;
}
}
输出结果
rue
0
2、深拷贝和浅拷贝
浅拷贝:直接将栈中的引用指向赋值的地址空间,那么这两个对象就指向同一个地址,一个改变另一个也会改变
深拷贝:另开一个内存空间,将赋值的对象所有属性取值都复制一遍,这样相当于是两个对象,不同的内存空间。
public Test {
public static void main(String[] args) {
BitSet bit = new BitSet();
bit.set(0);
BitSet bit2 = new BitSet();
bit2.set(1);
// 浅拷贝,直接将引用的地址给传给bit,这样bit2和bit指向同一块地址
bit = bit2;
bit2.set(2);
System.out.println(bit.get(2) + " " + bit2.get(2));
// 深拷贝,在bit2的引用地址数据基础上,重新开辟新地址(或者bit原有的地址),把bit2的所有取值复制过去
// bit指向的事另外一块内存地址,只是这个内存地址有着和bit2一样的对象取值
// 但是bit2的改变不会影响bit
bit2.set(3);
bit = (BitSet) bit2.clone();
bit2.set(5);
System.out.println(bit.get(5) + " " + bit2.get(5));
}
}
输出结果
true true
false true