1.对象和类的简单解析

1.对象和类的简单解析 1.1.对象的简单内存

1.对象和类的简单解析

堆(Heap)

此内存区域的功能是存放对象的实例,存放由new创建的对象或者内存数组,在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。几乎所有的对象都在这里分配,注意:对象的属性跟局部变量可是不一个概念,局部变量存储在栈中,对象的属性存在堆中

在堆中产生一个数组或对象之后,还可以在栈中定义一个特殊的变量p1,让栈中的这个变量赋值等于数组或对象在堆内存中的首地址。

例如:Person p1 = new Person();

栈中的这个变量就是数组或对象的引用变量也就是引用类型的数据,保存的是对象在堆中的首地址,以后就可以在程序中使用栈中的变量p1来访问堆中的数组或者对象,引用类型的变量就相当于为在堆内存中的数组或者对象所在的地址起的一个别名(可以理解下C语言的指针),便于我们程序的理解,总不能直接用内存地址作为变量使用,可读性太差。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其他作用域之外后边释放。而数组和对象本省在堆中分配,即使程序运行到使用new产生的数组或者对象的语句所在的代码块之外,数组和对象本省占据的内存不会被释放。数组和对象在没有引用变量指向它的时候,才变为垃圾,不能再被使用,在随后的一个不确定时间被垃圾回收器收走(释放掉)。这也是Java比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是Java中的指针。

栈(Stack),虚拟机栈

一般是指虚拟机栈,此处内存用于存储局部变量(方法中的变量都是局部变量,所以栈中保存的可以是基本数据类型的变量,也可以是对象的首地址这种引用类型的变量)等,局部变量表存放了编译期可知长度的各种基本数据类型(),对象引用(reference类型,它不是对象本身,是对象在堆内存中的首地址)

在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后(比如,在函数A中调用函数B,在函数B中定义变量a,变量a的作用域只是函数B,在函数B运行以后,变量a会自动被销毁。分配给它的内存会被回收),Java会自动释放掉为该变量分配的内存空间,该内存空间可以立即另做他用。

方法区(Method Area)

用于存储已经被类加载器加载的类信息,常量,静态变量等数据;

本地方法栈

程序计数器

2.1.程序分析

实例1:

package com.ethan.objandthis1; public class Demo2 { public static void main(String[] args) { Person per1 = new Person() ; Person per2 = new Person() ; per1.name="张三" ; per1.age=30 ; per2.age=33 ; per1.tell(); per2.tell(); } } class Person { String name; int age; boolean isMale; public void tell() { System.out.println("姓名:"+name+",年龄:"+age); } }

对上面的程序进行内存分析如下图:

1.对象和类的简单解析

实例2:

package com.ethan.objandthis1; public class Demo2 { public static void main(String[] args) { Person per1 = new Person() ; Person per2 = new Person() ; per1.name="张三" ; per2.name="李四" ; Person per3 = per1;//注意 per1.age=30 ; per2.age=33 ; per3.age=20;//注意 System.out.println(per1.age);//注意 } } class Person { String name; int age; boolean isMale; public void tell() { System.out.println("姓名:"+name+",年龄:"+age); } }

对上面的程序进行内存分析如下图:

1.对象和类的简单解析

总结:

实际上所谓的引用传递,就是将一个堆内存空间的使用权交给多个栈内存空间,每个栈内存空间都可以修改堆内存空间的内容;

引用类型就是指同一个堆内存可以被多个栈内存指向就如同上面的per3和per1,两个引用变量都可以操作堆内存中的同一个对象per1;

通过new操作,才能实例化对象,也就是在堆中为对象开辟内存空间,而上述的per3操作只是声明了一个引用变量;

在Java中主要存在4块内存空间,这些内存的名称及作用如下:

  1) 栈内存空间:保存所有对象的名称。

  2)堆内存空间:保存每个对象的具体属性内容。

  3)全局数据区:保存static类型的属性值。

  4)全局代码区:保存所有的方法定义。

3.1.属性(成员变量)和局部变量的对比

相同点:

都是变量,变量的先声明后使用,定义变量的格式,都有其对应的作用域;

不同点:

在类中定义和声明的位置不一样

属性:直接定义在类中;

局部变量:声明在方法内,形参,代码块,构造器参数,构造器内部变量

属性需要加权限修饰符,指明其权限范围,private,protected,默认,public

属性有默认初始化值,局部变量没有默认赋值,意味着我们调用时候需要显式赋值,声明局部变量时必须初始化值

在内存中加载的位置不一样

属性(非static类型的属性)加载到堆空间;

局部变量加载到栈空间;

以下学习来自bravo1988 - 知乎 (zhihu.com)的java小册!!!

4.1. 关于java中方法的引用

我们知道,在Java中对象是在堆空间中生成的,属性产生赋值的数据会在堆空间占据一定内存开销。而方法只有一份。

那么,方法为什么被设计成只有一份呢?

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zzzfyf.html