基本类型数据在内存中的存储非常简单,引用类型是把对象的地址放到栈内存中,数据放在堆内存中。在这通过几个小程序简单描述一下引用类型数据在内存中的存储过程:
class Person{
String name;
int age;
void say(){
System.out.println("姓名:"+name+",年龄:"+age);
}
}
public class Demo01{
public static void main(String args[]){
Person p1=new Person();
Person p2=new Person();
p1.name="张三";
p1.age=20;
p2=p1;
p1.say();
p2.say();
p2.name="李四";
p2.age=40;
p1.say();
p2.say();
}
}
上面的程序先新建了一个Person类,里面有两个成员变量还有一个成员方法。然后创建了一个Demo01类。执行如下代码:
Person p1=new Person;
Person p2=new Person();
就会为两个Person实例对象分配内存空间,将两个对象初始化,内存分配如图1所示:
执行
p1.name="张三";
p1.age=20;为实例对象p1赋值,内存分布如图2所示:
执行
p2=p1;是将实例对象p2指向实例对象p1的内存空间,原来为实例对象p1分配的内存空间就会失去指向,这样当系统执行垃圾(GC)技术时就会将这一部分内存释放。内存分步如图3所示:
执行
p1.say();
p2.say();
就会输出:
姓名:张三,年龄:20
姓名:张三,年龄:20
执行
p2.name="李四";
p2.age=40;
就会将原先的值覆盖,内存分配如图4所示:
执行
p1.say();
p2.say();
就会输出
姓名:李四,年龄:40
姓名:李四,年龄:40
这就是引用类型数据的存储过程。java程序采用这种存储方式主要有两个原因:
1.栈内存存取速度非常快,仅次于寄存器。2.与垃圾回收机制(GC)相连,有利于机制删除没有指向的堆内存数据,释放内存空间。
上面的程序执行
p2=p1;
这条语句后,将p2指向了p1所指向的数据并不能完成复制功能,我们可以稍作修改就可以完成复制功能,程序如下:
class Person{
String name;
int age;
void say(){
System.out.println("姓名:"+name+",年龄:"+age);
}
}
public class Demo02{
public static void main(String args[]){
Person p1=new Person();
Person p2=new Person();
p1.name="张三";
p1.age=20;
p2.name=p1.name;
p2.age=p1.age;
p1.say();
p2.say();
p2.name="李四";
p2.age=40;
p1.say();
p2.say();
}
}
这个程序的输出结果是:
姓名:张三,年龄:20
姓名:张三,年龄:20
姓名:张三,年龄:20
姓名:李四,年龄:40
我们来分析它的内存存储过程,执行代码
Person p1=new Person();
Person p2=new Person();
p1.name="张三";
p1.age=20;
它的存储过程如图1和图2相同,执行代码
p2.name=p1.name;
p2.age=p1.age;
它并没有将p2指向p1所指向的数据,而是将p1所指向的数据复制给p1所指向的数据。它的内存分配过程如图5所示:
执行代码
p1.say();
p2.say();
就会输出
姓名:张三,年龄:20
姓名:张三,年龄:20
执行代码
p2.name="李四";
p2.age=40;
修改了p2所指向的数据的值,但没有修改p1所指向的数据的值。内存分配过程如图6所示:
执行代码
p1.say();
p2.say();
就会输出
姓名:张三,年龄:20
姓名:李四,年龄:40
下面我们看下一个程序
class Person{
String name;
int age;
public void setName(String name){
this.name=name;
}
public void setAge(int age){
this.age=age;
}
public String getName(){
return name;
}
public int age(){
return age;
}
public void say(){
System.out.println("姓名:"+name+",年龄:"+age);
}
}
public class Demo03{
public static void main(String args[]){
Person[] per=new Person[2];
per[0]=new Person();
per[1]=new Person();
per[0].setName("张三");
per[0].setAge(20);
per[1].setName("李四");
per[1].setAge(40);
for(int i=0;i<per.length;i++){
per[i].say();
}
}
}
上面的程序输出结果为
姓名:张三,年龄:20
姓名:李四,年龄:40
此程序首先建立一个Person类,里面有成员变量和成员方法,然后定义一个Demo03类,执行代码
Person[] per=new Person[2];
per[0]=new Person();
per[1]=new Person();
建立一个Person对象的数组并初始化,这里的初始化只是将数组元素指向null,而并没有在堆内存中分配空间,内存存储如图7所示:
执行代码
per[0]=new Person();
per[1]=new Person();
这才是为数组元素开辟了堆内存空间并初始化,如图8所示:
执行代码
per[0].setName("张三");
per[0].setAge(20);
per[1].setName("李四");
per[1].setAge(40);
将张数据存储到各个数组元素所指向的堆内存中,如图9所示:
执行代码
for(int i=0;i<per.length;i++){
per[i].say();
}
是将数组中的值输出出来,就会输出以上输出结果。
java引用类型的存储过程就是这样。这只是在下的一个小见解,可能有不到位或不
正确的地方,欢迎各位朋友提出见解,共同分享知识。