Java实例化对象过程中的内存分配:

https://blog.csdn.net/qq_36934826/article/details/82685791

问题引入这里先定义一个很不标准的“书”类,这里为了方便演示就不对类的属性进行封装了。
class Book{    String name;    //书名    double price;   //价格    public void getInfo(){        System.out.println("name:"+name+";price:"+price);    }}1问题引入这里先定义一个很不标准的“书”类,这里为了方便演示就不对类的属性进行封装了。
class Book{    String name;    //书名    double price;   //价格    public void getInfo(){        System.out.println("name:"+name+";price:"+price);    }}1234567在这个类中定义了两个属性和一个方法,当然也是可以定义多和类和多个方法的。 类现在虽然已经定义好了,但是一个类要使用它必须要实例化对象,那么对象的定义格式有一下两种格式:
//声明并实例化对象: 类名称 对象名称 = new 类名称()Book book = new Book();123//分步完成声明和实例操作: // |- 声明对象: 类名称 对象名称 = null;Book book = null;// |- 实例化对象: 对象名称 = new 类名称();book = new Book();12345对象属于引用数据类型,其和基本数据类型最大的不同在于引用数据类型需要进行内存分配,而关键字new主要的功能就是开辟内存空间,也就是说只要是使用引用数据类型就必须使用关键字new来开辟空间。有些时候我们需要对对象属性进行操作,那么其中的堆栈内存空间又是如何分配的呢?接下来我们来分析一下其中的过程。
堆内存与栈内存如果想对对象操作的过程进行内存分析,首先要了解两块内存空间的概念:
堆内存:保存每一个对象的属性内容,堆内存需要用关键字new才能开辟。栈内存:保存的是一块堆内存的地址。堆内存很好理解,可能有人会有疑问为什么会有栈内存,举个例子,好比学校有很多教室,每个教室有一个门牌号,教室内放了很多的桌椅等等,这个编号就好比地址,老师叫小明去一个教室拿东西,老师必须把房间号告诉小明才能拿到,也就是为什么地址必须存放在一个地方,而这个地方在计算机中就是栈内存。
对象空属性我们先实例化一个对象,并对其的属性不设置任何值
public class Test{    public static void main(String args[]){         Book book = new Book();         book.getInfo();    }}123456运行结果如下:
name:null;price:0.01其内存变化图如下:

使用关键字new就在栈内存中开辟一个空间存放book对象,并且指向堆内存的一个空间,此时并未对其赋值,所以始终指向默认的堆内存空间。
操作对象属性我们先声明并实例化Book类,并对实例出的book对象操作其属性内容。
public class Test{    public static void main(String args[]){         Book book = new Book();         book.name = "深入理解JVM";         book.price = 99.8;         book.getInfo();    }}12345678编译执行后的结果如下:
name:深入理解JVM;price:99.81内存变化图如下:

分步实例化对象示例代码如下:
public class Test{    public static void main(String args[]){         Book book = null;  //声明对象         book = new Book(); //实例化对象         book.name = "深入理解JVM";         book.price = 99.8;         book.getInfo();    }}123456789很明显结果肯定和前面一样
name:深入理解JVM;price:99.81表面没什么区别,但是内存分配过程却不一样,接下来我们来分析一下

任何情况下只要使用了new就一定要开辟新的堆内存空间,一旦堆内存空间开辟了,里面就一定会所有类中定义的属性内容,此时所有的属性内容都是其对应数据类型的默认值。
直观的说就是栈内存先要指向一个null,然后等待开辟新的栈内存空间后才能指向其属性内容。
NullPointerException的出现那么如果使用了没有实例化的对象,就会出现最常见也是最让人头疼的一个异常NullPointerException,像下面的代码
public class Test{    public static void main(String args[]){         Book book = null;//         book = new Book();   //实例化的这一步被注释         book.name = "深入理解JVM";         book.price = 99.8;         book.getInfo();    }}123456789在编译的过程是不会出错的,因为只有语法错误才会在编译时中断,而这种逻辑性错误能成功编译,但是执行的时候却会抛出NullPointerException异常。 运行结果:
Exception in thread "main" java.lang.NullPointerException at language.Test.main(Test.java:19)1空指针异常是平时遇到最多的一类异常,只要是引用数据类型都有可能出现它。这种异常的出现也是很容易理解的,犹如你说今天被一只恐龙追着跑,恐龙早就在几个世纪前就灭绝了,现实生活中不可能存在,当然人们就会认为你说的这句话是谎言。在程序中也一样,没有被实例化的对象直接调用其中的属性或者方法,肯定会报错。
引用数据分析引用是整个java中的核心精髓,引用类似于C++中的指针概念,但是又比指针的概念更加简单。 举个简单的例子,比如李华的小名叫小华,一天李华因为生病向老师请假了,老师问今天谁请假了,说李华请假了和小华请假了都是一个意思,小华是李华的别名,他们两个都是对应一个个体。 如果代码里面声明两个对象,并且使用了关键字new为两个对象分别进行了对象的实例化操作,那么一定是各自占用各自的堆内存空间,并且不会互相影响。
例如:声明两个对象
public class Test{    public static void main(String args[]){         Book bookA = new Book();         Book bookB = new Book();
         bookA.name = "深入理解JVM";         bookA.price = 99.8;         bookA.getInfo();
         bookB.name = "Java多线程";         bookB.price = 69.8;         bookB.getInfo();    }}1234567891011121314运行结果如下:
name:深入理解JVM;price:99.8name:Java多线程;price:69.812我们来分析一下内存的变化

接下来我们看看那对象引用传递
例如:对象引用传递
public class Test{    public static void main(String args[]){         Book bookA = new Book();   //声明并实例化对象         Book bookB = null;         //声明对象         bookA.name = "深入理解JVM";         bookA.price = 99.8;         bookB = bookA;             //引用传递         bookB.price = 69.8;         bookA.getInfo();    }}1234567891011运行结果如下:
name:深入理解JVM;price:69.81严格来讲bookA和bookB里面保存的是对象的地址信息,所以以上的引用过程就属于将bookA的地址赋给了bookB,此时两个对象指向的是同一块堆内存空间,因此任何一个对象修改了堆内存之后都会影响其他对象。

一块堆内存可以同时被多个栈内存所指向,但是反过来,一块栈内存只能保存一块堆内存空间的地址。
垃圾的产生先看如下代码:
public class Test{    public static void main(String args[]){         Book bookA = new Book();   //声明并实例化对象         Book bookB = new Book();   //声明并实例化对象         bookA.name = "深入理解JVM";         bookA.price = 99.8;         bookB.name = "Java多线程";         bookB.price = 69.8;         bookB = bookA;             //引用关系         bookB.price = 120.8;         bookA.getInfo();    }}12345678910111213运行结果如下:
name:深入理解JVM;price:120.81整个过程内存又发生了什么变化呢?我们来看一下 
在此过程中原来bookB所指向的堆内存无栈内存指向,一块没有任何栈内存指向的堆内存空间就将成为垃圾,等待被java中的回收机制回收,回收之后会释放掉其占用的空间。
虽然在java中支持了自动的垃圾收集处理,但是在代码的编写过程中应该尽量减少垃圾空间的产生。
欢迎来我的博客网站逛一逛~blog.beifengtz.com--------------------- 作者:beifengtz 来源:CSDN 原文:https://blog.csdn.net/qq_36934826/article/details/82685791 版权声明:本文为博主原创文章,转载请附上博文链接!234567在这个类中定义了两个属性和一个方法,当然也是可以定义多和类和多个方法的。 类现在虽然已经定义好了,但是一个类要使用它必须要实例化对象,那么对象的定义格式有一下两种格式:
//声明并实例化对象: 类名称 对象名称 = new 类名称()Book book = new Book();123//分步完成声明和实例操作: // |- 声明对象: 类名称 对象名称 = null;Book book = null;// |- 实例化对象: 对象名称 = new 类名称();book = new Book();12345对象属于引用数据类型,其和基本数据类型最大的不同在于引用数据类型需要进行内存分配,而关键字new主要的功能就是开辟内存空间,也就是说只要是使用引用数据类型就必须使用关键字new来开辟空间。有些时候我们需要对对象属性进行操作,那么其中的堆栈内存空间又是如何分配的呢?接下来我们来分析一下其中的过程。
堆内存与栈内存如果想对对象操作的过程进行内存分析,首先要了解两块内存空间的概念:
堆内存:保存每一个对象的属性内容,堆内存需要用关键字new才能开辟。栈内存:保存的是一块堆内存的地址。堆内存很好理解,可能有人会有疑问为什么会有栈内存,举个例子,好比学校有很多教室,每个教室有一个门牌号,教室内放了很多的桌椅等等,这个编号就好比地址,老师叫小明去一个教室拿东西,老师必须把房间号告诉小明才能拿到,也就是为什么地址必须存放在一个地方,而这个地方在计算机中就是栈内存。
对象空属性我们先实例化一个对象,并对其的属性不设置任何值
public class Test{    public static void main(String args[]){         Book book = new Book();         book.getInfo();    }}123456运行结果如下:
name:null;price:0.01其内存变化图如下:

使用关键字new就在栈内存中开辟一个空间存放book对象,并且指向堆内存的一个空间,此时并未对其赋值,所以始终指向默认的堆内存空间。
操作对象属性我们先声明并实例化Book类,并对实例出的book对象操作其属性内容。
public class Test{    public static void main(String args[]){         Book book = new Book();         book.name = "深入理解JVM";         book.price = 99.8;         book.getInfo();    }}12345678编译执行后的结果如下:
name:深入理解JVM;price:99.81内存变化图如下:

分步实例化对象示例代码如下:
public class Test{    public static void main(String args[]){         Book book = null;  //声明对象         book = new Book(); //实例化对象         book.name = "深入理解JVM";         book.price = 99.8;         book.getInfo();    }}123456789很明显结果肯定和前面一样
name:深入理解JVM;price:99.81表面没什么区别,但是内存分配过程却不一样,接下来我们来分析一下

任何情况下只要使用了new就一定要开辟新的堆内存空间,一旦堆内存空间开辟了,里面就一定会所有类中定义的属性内容,此时所有的属性内容都是其对应数据类型的默认值。
直观的说就是栈内存先要指向一个null,然后等待开辟新的栈内存空间后才能指向其属性内容。
NullPointerException的出现那么如果使用了没有实例化的对象,就会出现最常见也是最让人头疼的一个异常NullPointerException,像下面的代码
public class Test{    public static void main(String args[]){         Book book = null;//         book = new Book();   //实例化的这一步被注释         book.name = "深入理解JVM";         book.price = 99.8;         book.getInfo();    }}123456789在编译的过程是不会出错的,因为只有语法错误才会在编译时中断,而这种逻辑性错误能成功编译,但是执行的时候却会抛出NullPointerException异常。 运行结果:
Exception in thread "main" java.lang.NullPointerException at language.Test.main(Test.java:19)1空指针异常是平时遇到最多的一类异常,只要是引用数据类型都有可能出现它。这种异常的出现也是很容易理解的,犹如你说今天被一只恐龙追着跑,恐龙早就在几个世纪前就灭绝了,现实生活中不可能存在,当然人们就会认为你说的这句话是谎言。在程序中也一样,没有被实例化的对象直接调用其中的属性或者方法,肯定会报错。
引用数据分析引用是整个java中的核心精髓,引用类似于C++中的指针概念,但是又比指针的概念更加简单。 举个简单的例子,比如李华的小名叫小华,一天李华因为生病向老师请假了,老师问今天谁请假了,说李华请假了和小华请假了都是一个意思,小华是李华的别名,他们两个都是对应一个个体。 如果代码里面声明两个对象,并且使用了关键字new为两个对象分别进行了对象的实例化操作,那么一定是各自占用各自的堆内存空间,并且不会互相影响。
例如:声明两个对象
public class Test{    public static void main(String args[]){         Book bookA = new Book();         Book bookB = new Book();
         bookA.name = "深入理解JVM";         bookA.price = 99.8;         bookA.getInfo();
         bookB.name = "Java多线程";         bookB.price = 69.8;         bookB.getInfo();    }}1234567891011121314运行结果如下:
name:深入理解JVM;price:99.8name:Java多线程;price:69.812我们来分析一下内存的变化

接下来我们看看那对象引用传递
例如:对象引用传递
public class Test{    public static void main(String args[]){         Book bookA = new Book();   //声明并实例化对象         Book bookB = null;         //声明对象         bookA.name = "深入理解JVM";         bookA.price = 99.8;         bookB = bookA;             //引用传递         bookB.price = 69.8;         bookA.getInfo();    }}1234567891011运行结果如下:
name:深入理解JVM;price:69.81严格来讲bookA和bookB里面保存的是对象的地址信息,所以以上的引用过程就属于将bookA的地址赋给了bookB,此时两个对象指向的是同一块堆内存空间,因此任何一个对象修改了堆内存之后都会影响其他对象。

一块堆内存可以同时被多个栈内存所指向,但是反过来,一块栈内存只能保存一块堆内存空间的地址。
垃圾的产生先看如下代码:
public class Test{    public static void main(String args[]){         Book bookA = new Book();   //声明并实例化对象         Book bookB = new Book();   //声明并实例化对象         bookA.name = "深入理解JVM";         bookA.price = 99.8;         bookB.name = "Java多线程";         bookB.price = 69.8;         bookB = bookA;             //引用关系         bookB.price = 120.8;         bookA.getInfo();    }}12345678910111213运行结果如下:
name:深入理解JVM;price:120.81整个过程内存又发生了什么变化呢?我们来看一下 
在此过程中原来bookB所指向的堆内存无栈内存指向,一块没有任何栈内存指向的堆内存空间就将成为垃圾,等待被java中的回收机制回收,回收之后会释放掉其占用的空间。
虽然在java中支持了自动的垃圾收集处理,但是在代码的编写过程中应该尽量减少垃圾空间的产生。--------------------- 作者:beifengtz 来源:CSDN 原文:https://blog.csdn.net/qq_36934826/article/details/82685791 版权声明:本文为博主原创文章,转载请附上博文链接!

Java实例化对象过程中的内存分配的更多相关文章

  1. java中子类实例化过程中的内存分配

    知识点: 子类继承父类之后,实例化子类时,内存中子类是如何分配内存的呢? 下面,自己会结合一个例子,解释一下,一个子类实例化过程中,内存是如何分配的 参考博客:http://www.cnblogs.c ...

  2. Java 程序运行过程中的内存分析

    作为 java 程序员,都应该知道 Java 程序运行在 JVM(Java Virtual Machine,Java 虚拟机)上,可以把 JVM 理解成 Java 程序和操作系统之间的桥梁,JVM 实 ...

  3. Java中对象创建时的内存分配

    一.前言知识铺垫   1.逃逸对象:在一个方法内创建的对象没有被外界引用则称该对象为未逃逸的对象. 2.JDK1.6以后的HotSpot虚拟机支持运行时的对象逃逸分析. 3.JVM中的参数配置: 1) ...

  4. Java中类,对象,方法的内存分配

    Java中类,对象,方法的内存分配 以下针对引用数据类型: 在内存中,类是静态的概念,它存在于内存中的CodeSegment中. 当我们使用new关键字生成对象时,JVM根据类的代码,去堆内存中开辟一 ...

  5. Java中的内存分配机制

    Java的内存分为两种:一种是栈内存,一种是堆内存. 在函数中定义的一些基本类型变量和对象的引用都在函数的栈内存中分配.当在一个代码块中定义一个变量的时候,java就在栈中为其分配内存,当超过作用域的 ...

  6. Java虚拟机中的内存分配

    java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途以及创建和销毁的时间. 栈:存放的是局部变量,包括:1.用来保存基本数据类型的值:2.保存类 ...

  7. Java基础-Java中的内存分配与回收机制

    Java基础-Java中的内存分配与回收机制 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一. 二.

  8. 《深入理解Java虚拟机》学习笔记之内存分配

    JVM在执行Java程序的过程中会把它所管理的内存划分若干个不同的数据区域,如下图: 大致可以分为两类:线程私有区域和线程共享区域. 线程私有区域 程序计数器(Program Counter Regi ...

  9. Netty 中的内存分配浅析

    Netty 出发点作为一款高性能的 RPC 框架必然涉及到频繁的内存分配销毁操作,如果是在堆上分配内存空间将会触发频繁的GC,JDK 在1.4之后提供的 NIO 也已经提供了直接直接分配堆外内存空间的 ...

随机推荐

  1. Sql Server有主外键关系时添加、删除数据

    当表之间有主外键关系时删除数据会被约束,添加.删除失败 解决办法,我们可以先把主外键关系的检查约束给关掉 → 然后删除数据 → 之后再把约束打开 查询出关掉所有外键约束的语句 SELECT 'ALTE ...

  2. docker系列之六容器数据卷

    docker之容器数据卷 一.容器数据卷 docker容器运行的时候,会产生一系列的文件,那么我们希望容器产生的数据能提供给其他的容器使用,也就是说怎么实现容器间的数据的共享呢?这就需要用到我们所提到 ...

  3. 运动的border,仿当当简易效果

    突然想到以前看到当当上有个效果,当鼠标移上去,图片边框是运动添加上的,还以为是css3或者是canvas做的呢,做完幽灵按钮后,才知道,so  easy,只不过是animate+position的杰作 ...

  4. Postman如何进行参数化

    前言 Postman作为一款接口测试工具,受到了非常多的开发工程师的拥护. 那么做为测试,了解Postman这款工具就成了必要的了. 这篇文章就是为了解决Postman怎么进行参数化的. 全局变量 全 ...

  5. 5.创建执行线程的方式之三 :实现Callable 接口

    Callable 接口 一.Java 5.0 在 java.util.concurrent 提供了 一个新的创建执行线程的方式(之前有继承Thread 和 实现Runnable):Callable 接 ...

  6. 什么是mvvm设计模式

    目前比较流行的几个框架,例如vue.js.react.js.avalon.angular.js等,给自己的定位都是属于mvvm类型框架,那么什么是mvvm框架呢?mvvm是什么意思呢? 聊到mvvm就 ...

  7. Linux命令——cp、rm、mv、touch、file、dir

    cp copy 拷贝文件 拷贝过程不指定目标文件名 则目标文件名和源文件名一样 [root@WebServer ~]# cp /91xueit/teacher.txt 51cto/ 拷贝过程指定目标文 ...

  8. 用js刷剑指offer(跳台阶)

    题目描述 一只青蛙一次可以跳上1级台阶,也可以跳上2级.求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果). 牛客网链接 思路 这一题和斐波那契数列思路完全一样. 假如青蛙从第n个 ...

  9. Jmeter练习

    首页 新随笔 管理   Jmeter接口测试实例-牛刀小试   本次测试的是基于HTTP协议的接口,主要是通过Jmeter来完成接口测试,借此熟悉Jmeter的基本操作. 本次实战,我是从网上找的接口 ...

  10. Python基础之类

    一.摘要 面向对象编程 是最有效的软件编写方法之一.在面向对象编程中,你编写表示现实世界中的事物和情景的类,并基于这些类来创建对象.编写类时,你定义一大类对象都有的通用行为.基于类创建对象 时,每个对 ...