Java学习1:图解Java内存分析详解(实例)
2017-11-14 10:49
316 查看
随着工作的深入,越发需要重新梳理一遍Java知识点,本系列是重新学习Java所写。
堆空间(heap),不连续的空间,用于存放new出的对象,或者说是类的实例。
方法区(method),方法区在堆空间内,用于存放①类的代码信息;②静态变量和方法;③常量池(字符串敞亮等,具有共享机制)。
Java中除了基本数据类型,其他的均是引用类型,包括类、数组等等。
数据类型的默认值
基本数据类型默认值:
数值型:0
浮点型:0.0
布尔型:false
字符型:\u0000
引用类型:null
变量初始化
成员变量可不初始化,系统会自动初始化;
局部变量必须由程序员显式初始化,系统不会自动初始化。
②走到Student,以同样的逻辑对Student类进行加载;静态成员;常量池(”studying”)。
③走到stu,stu在main方法内部,因而是局部变量,存放在栈空间中。
④走到new Student,new出的对象(实例),存放在堆空间中,以方法区的类信息为模板创建实例。
⑤‘’=‘’赋值操作,把new Student的地址告诉stu变量,stu通过四字节的地址(十六进制),引用该实例。
如下图:
⑥⑦⑧的过程如下图:
如下图:
⑨重新将Computer实例的brand属性指向”Dell”常量,那stu.computer.brand指向谁呢?Dell还是Hasse?
根据刚才的分析可知:
stu通过地址引用Student实例,而该实例的computer的指向和c的指向是同一个Computer实例,因而改变该Computer实例的brand属性的指向,两者都会改变。
举个例子:
访问大明,和访问大明的儿子的爸爸,实质上访问的是同一个对象:大明。
因而,最终的结果是true。
结果会如何呢?
根据常量池具有共享性,可知并不会生成新的常量”Dell”,而是会把str通过地址指向原来的”Dell”,因而结果是true。
首先需要明白以下几点:
栈空间(stack),连续的存储空间,遵循后进先出的原则,用于存放局部变量。堆空间(heap),不连续的空间,用于存放new出的对象,或者说是类的实例。
方法区(method),方法区在堆空间内,用于存放①类的代码信息;②静态变量和方法;③常量池(字符串敞亮等,具有共享机制)。
Java中除了基本数据类型,其他的均是引用类型,包括类、数组等等。
数据类型的默认值
基本数据类型默认值:
数值型:0
浮点型:0.0
布尔型:false
字符型:\u0000
引用类型:null
变量初始化
成员变量可不初始化,系统会自动初始化;
局部变量必须由程序员显式初始化,系统不会自动初始化。
实例进行分析。
创建类
分别是Student、Computer、Test,代码如下:public class Student { int score; int age; String name; Computer computer; public void study() { System.out.println("studying..."); } }
public class Computer { int price; String brand; }
public class Test { public static void main(String[] args) { Student stu = new Student(); stu.name = "xiaoming"; stu.age = 10; stu.study(); Computer c = new Computer(); c.brand = "Hasse"; System.out.println(c.brand); stu.computer = c; System.out.println(stu.computer.brand); // System.out.println("----------------------------------------"); // // c.brand = "Dell"; // // System.out.println(c.brand); // System.out.println(stu.computer.brand); // // System.out.println(stu.computer.brand == c.brand); } }
代码分析
我们知道,程序的入口是main(),因而从main方法从上到下、从左到右进行分析。Student stu = new Student();
①首先,Java虚拟机(JVM)去方法区寻找是否有Test类的代码信息,如果存在,直接调用。如果没有,通过类加载器(ClassLoader)把.class字节码加载到内存中,并把静态变量和方法、常量池加载(”xiaoming”、”Hasse”)。②走到Student,以同样的逻辑对Student类进行加载;静态成员;常量池(”studying”)。
③走到stu,stu在main方法内部,因而是局部变量,存放在栈空间中。
④走到new Student,new出的对象(实例),存放在堆空间中,以方法区的类信息为模板创建实例。
⑤‘’=‘’赋值操作,把new Student的地址告诉stu变量,stu通过四字节的地址(十六进制),引用该实例。
如下图:
stu.name = “xiaoming”;
⑥stu通过引用new Student实例的name属性,该name属性通过地址指向常量池的”xiaoming”敞亮。stu.age = 10;
⑦s实例的age属性是基本数据类型,基本数据类型直接赋值。stu.study();
⑧调用实例的方法时,并不会在实例对象中生成一个新的方法,而是通过地址指向方法区中类信息的方法。⑥⑦⑧的过程如下图:
Computer c = new Computer();
同stu变量的生成过程。c.brand = “Hasse”;
同stu.name = “xiaoming”过程。stu.computer = c;
⑨把c对象对Computer实例的引用赋值给Student实例的computer属性。亦即:该Student实例的computer属性指向该Computer类的实例。如下图:
拓展
改变brand的地址指向。
为进一步理解,我们把注释内容去掉:⑨重新将Computer实例的brand属性指向”Dell”常量,那stu.computer.brand指向谁呢?Dell还是Hasse?
c.brand = "Dell";
根据刚才的分析可知:
stu通过地址引用Student实例,而该实例的computer的指向和c的指向是同一个Computer实例,因而改变该Computer实例的brand属性的指向,两者都会改变。
举个例子:
访问大明,和访问大明的儿子的爸爸,实质上访问的是同一个对象:大明。
因而,最终的结果是true。
理解字符串常量及常量池
下面我们添加新的代码,如下:String str = "Dell"; System.out.println(c.brand == str);
结果会如何呢?
根据常量池具有共享性,可知并不会生成新的常量”Dell”,而是会把str通过地址指向原来的”Dell”,因而结果是true。
相关文章推荐
- Java学习13:面向对象-多态(Polymorphism)内存分析图解
- 学习笔记-java内存分析
- java内存分析+String+equals详解
- java学习之路----内存的分析
- 跟着实例学习java多线程4-内存可见性
- Java 程序内存分析--详解 挺清楚的~~
- JAVA学习之内存分析
- 内存分析----------------图解Java继承内存分配
- java学习之旅52--数组_数组基本概念_内存分析
- Java学习之二维数组定义与内存分配详解
- java学习之旅60--数组_多维数组_基本语法_内存分析
- Java 学习笔记 (13) - 基本内存分析 和 垃圾回收机制
- java学习之旅36--面向对象_09_static变量和方法_内存分析static
- Java学习-007-Log4J 日志记录配置文件详解及实例源代码
- (Java2D 学习笔记系列) (一)一个简单的图像填充实例及其分析理解
- java 从零开始,学习笔记之基础入门<线程及实例分析>(十九)
- java学习之旅37--面向对象_10_this隐式参数_内存分析
- 韩顺平_轻松搞定网页设计(html+css+javascript)_第30讲_类和对象细节_创建对象的几种方式_js对象内存分析_学习笔记_源代码图解_PPT文档整理
- Java学习之类加载全过程_JVM内存分析_反射机制核心原理_常量池理解
- 深入分析Java内存区域的使用详解