对象的创建和使用:内存解析
- 堆(Heap):此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。这一点在Java虚拟机规范中的描述是:所有的对象实例以及数组都要在堆上分配。
- 栈(Stack):通常所说的栈,是指虚拟机栈, 用于存储局部变量等。局部变量表存放了编译期可知长度的各种基本数据类型(boolean、byte、char 、 short 、 int 、 float 、 long 、double)、对象引用(reference类型,它不等同于对象本身,是对象在堆内存的首地址)。 方法执行完,自动释放。
- 方法区(Method Area),用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
例如:建一个penson类,设计属性和方法后,在main方法中创建对象,并调用person的属性和方法,依次案例进行内存分析。
public class PersonTest {
public static void main(String[] args) {
//调用属性
Person p1=new Person();
p1.name="Tom";
p1.age=18;
p1.isMale=true;
System.out.println(p1.name);
//调用方法
p1.eat();
p1.sleep();
p1.talk("Chinese");
System.out.println("*******************");
Person p2=new Person();
System.out.println(p2.name);
System.out.println(p2.isMale);
//*如果创建一个类的多个对象,则每个对象都有一套独立的属性(非static的)
//*意味着,如果我们修改一个对象的属性a,不影响另一个属性a的值
System.out.println("*******************");
//将p1对象地址值赋给p3,所有p1,p3指向堆中同一对象实体
Person p3=p1;
System.out.println(p3.name);
p3.age=10;
System.out.println(p1.age);
}
}
class Person{
//属性
String name;
int age;
boolean isMale;
//方法
public void eat(){
System.out.println("person can eat");
}
public void sleep(){
System.out.println("person can sleep");
}
public void talk(String language){
System.out.println("person can speak "+language);
}
}
输出结果:
Tom
person can eat
person can sleep
person can speak Chinese
*******************
null
false
*******************
Tom
10
##对象的内存分析
step1.
Person p1=new Person();
(1)只要是new,都会在堆中创建一个实体,这个实体会有一个地址值,假设首地址值为0x2ab
(2)在栈中开辟一个main方法的栈帧,其中,声明一个局部变量p1,“=”是将新创建的实体的首地址赋给变量p1
(3) 属性name,age, isMale 存在于堆中新创建的实体中
(注:下图中有处错误:堆中对象的属性Age的初始默认值应该为0,而不是null)
step2.
p1.name="Tom";
p1.age=18;
p1.isMale=true;
(1)
step3.
新建一个实体p2
Person p2=new Person();
System.out.println(p2.name);
System.out.println(p2.isMale);
step4.
在main中声明一个变量p3,把p1实体的首地址值赋给p3,
此时的p3与p1指向同一个对象,所有p3.name也是Tom。
又通过p3将age修改为10,所有p1再去调用时age=10
Person p3=p1;
System.out.println(p3.name);
p3.age=10;
System.out.println(p1.age);