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

问题引入

这里先定义一个很不标准的“书”类,这里为了方便演示就不对类的属性进行封装了。

class Book{String name;    //书名double price;   //价格public void getInfo(){System.out.println("name:"+name+";price:"+price);}
}

在这个类中定义了两个属性和一个方法,当然也是可以定义多和类和多个方法的。 类现在虽然已经定义好了,但是一个类要使用它必须要实例化对象,那么对象的定义格式有一下两种格式:

//声明并实例化对象: 类名称 对象名称 = new 类名称()
Book book = new Book();
//分步完成声明和实例操作: 
// |- 声明对象: 类名称 对象名称 = null;
Book book = null;
// |- 实例化对象: 对象名称 = new 类名称();
book = new Book();

对象属于引用数据类型,其和基本数据类型最大的不同在于引用数据类型需要进行内存分配,而关键字new主要的功能就是开辟内存空间,也就是说只要是使用引用数据类型就必须使用关键字new来开辟空间。有些时候我们需要对对象属性进行操作,那么其中的堆栈内存空间又是如何分配的呢?接下来我们来分析一下其中的过程。

堆内存与栈内存

如果想对对象操作的过程进行内存分析,首先要了解两块内存空间的概念:

  • 堆内存:保存每一个对象的属性内容,堆内存需要用关键字new才能开辟。
  • 栈内存:保存的是一块堆内存的地址。

堆内存很好理解,可能有人会有疑问为什么会有栈内存,举个例子,好比学校有很多教室,每个教室有一个门牌号,教室内放了很多的桌椅等等,这个编号就好比地址,老师叫小明去一个教室拿东西,老师必须把房间号告诉小明才能拿到,也就是为什么地址必须存放在一个地方,而这个地方在计算机中就是栈内存。

对象空属性

我们先实例化一个对象,并对其的属性不设置任何值

public class Test{public static void main(String args[]){Book book = new Book();book.getInfo();}
}

运行结果如下:

name:null;price:0.0

其内存变化图如下:

使用关键字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();}
}

编译执行后的结果如下:

name:深入理解JVM;price:99.8

内存变化图如下:

分步实例化对象

示例代码如下:

public class Test{public static void main(String args[]){Book book = null;  //声明对象book = new Book(); //实例化对象book.name = "深入理解JVM";book.price = 99.8;book.getInfo();}
}

很明显结果肯定和前面一样

name:深入理解JVM;price:99.8

表面没什么区别,但是内存分配过程却不一样,接下来我们来分析一下

任何情况下只要使用了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();}
}

在编译的过程是不会出错的,因为只有语法错误才会在编译时中断,而这种逻辑性错误能成功编译,但是执行的时候却会抛出NullPointerException异常。 运行结果:

Exception in thread "main" java.lang.NullPointerException at language.Test.main(Test.java:19)

空指针异常是平时遇到最多的一类异常,只要是引用数据类型都有可能出现它。这种异常的出现也是很容易理解的,犹如你说今天被一只恐龙追着跑,恐龙早就在几个世纪前就灭绝了,现实生活中不可能存在,当然人们就会认为你说的这句话是谎言。在程序中也一样,没有被实例化的对象直接调用其中的属性或者方法,肯定会报错。

引用数据分析

引用是整个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();}
}

运行结果如下:

name:深入理解JVM;price:99.8
name:Java多线程;price:69.8

我们来分析一下内存的变化

接下来我们看看那对象引用传递

例如:对象引用传递

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();}
}

运行结果如下:

name:深入理解JVM;price:69.8

严格来讲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();}
}

运行结果如下:

name:深入理解JVM;price:120.8

整个过程内存又发生了什么变化呢?我们来看一下

在此过程中原来bookB所指向的堆内存无栈内存指向,一块没有任何栈内存指向的堆内存空间就将成为垃圾,等待被java中的回收机制回收,回收之后会释放掉其占用的空间。

虽然在java中支持了自动的垃圾收集处理,但是在代码的编写过程中应该尽量减少垃圾空间的产生。

END

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/439490.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Python学习】 - sklearn学习 - KNN

前言: 针对一个完整的机器学习框架目前还没有总结出来,所以目前只能总结每一个单独的算法。由于现在研究的重点是算法,所以对于数据的处理,数据的分析和可视化呈现,在现阶段并不进行展示(这样容易陷入纠结…

重读经典:《End-to-End Object Detection with Transformers》

DETR 论文精读【论文精读】这一次朱毅博士给大家精读的论文是 DETR,是目标检测领域里程碑式的一个工作,文章收录于 ECCV20 。DETR 是 Detection Transformer 的缩写,作者使用 Transformer 简化了目标检测流程,不再需要进行 NMS&am…

Execute SQL Task 参数和变量的映射

Execute SQL Task能够执行带参数的SQL查询语句或存储过程(SP),通过SSIS的变量(Variable)对参数赋值。对于不同的Connection Manager,在Task中需要使用不同的符号(Parameter marker)来…

【Python学习】 - 手写数字识别 - python读入mnist数据集的多种方法

写在前面: 其实网上有很多读入mnist数据的代码,但是都是比较麻烦冗长的函数,本篇文章介绍几种不算很麻烦的,借用库函数读入数据的方法。 方法1: 方法2: 方法3:

Coursera自动驾驶课程第21讲:Dynamic Object Interactions

在第20讲《Coursera自动驾驶课程第20讲:Mission Planning in Driving Environments》 我们学习了任务规划中常用的三种图搜索算法:Breadth First Search、Dijkstra 和 A* 搜索。 在本讲中我们将讨论运动规划器中使用的方法,以处理动态物体和…

sql server 数据库忘记sa账户密码/ 无管理员账户解决办法

一、计算机超级管理员账户有数据库的管理员权限 用管理员账户登录数据库,直接修改sa账户密码即可。 二、数据库中没有管理员权限的账户 SQL Server 2005/2008提供了针对该情况的更好的灾难恢复方法,无需侵入master数据库,不会对master数据库…

机器学习编译第1讲:机器学习编译概述

MLC-机器学习编译-第一讲-机器学习编译概述课程主页:https://mlc.ai/summer22-zh/ 文章目录1.0 概述1.1 什么是机器学习编译1.2 为什么学习机器学习编译1.3 机器学习编译的关键要素1.3.1 备注:抽象和实现1.4 总结1.0 概述 机器学习应用程序已经无处不在…

重读经典:《The Craft of Research(1)》

跟读者建立联系【研究的艺术一】这一次李沐博士给大家精读的是一本关于论文写作的书籍。这本书总共包含四个大的章节,本期视频李沐博士介绍的是第一个章节:Research,Researchers,and Readers。 0. 前言 视频开头,李沐…

机器学习编译第2讲:张量程序抽象

02 张量程序抽象 【MLC-机器学习编译中文版】课程主页:https://mlc.ai/summer22-zh/ 文章目录2.1 元张量函数2.2 张量程序抽象2.2.1 张量程序抽象中的其它结构2.3 张量程序变换实践2.3.1 安装相关的包2.3.2 构造张量程序2.3.3 编译与运行2.3.4 张量程序变换2.3.5 通…

详解自动驾驶仿真数据集 SHIFT:A Synthetic Driving Dataset for Continuous Multi-Task Domain Adaptation

SHIFT:A Synthetic Driving Dataset for Continuous Multi-Task Domain Adaptation本文介绍一个新的自动驾驶仿真数据集:SHIFT,论文收录于 CVPR2022。适应连续变化的环境是自动驾驶系统一直以来要面临的挑战。然而,目前现有的图像…

TFS下的源代码控制

以下主要描述了: TFS源代码控制系统的基本场景如何把一个项目添加到源代码管理中如何与服务器同步如何做Check-In如何做分支与合并什么是上架与下架 我们知道工作项是项目管理的基本元素,但是一个项目的成功,光有工作项还是不够的。工作项说…

地平线:面向规模化量产的智能驾驶系统和软件开发

导读 7月27日,地平线在智东西公开课开设的「地平线自动驾驶技术专场」第3讲顺利完结,地平线智能驾驶应用软件部负责人宋巍围绕 《面向规模化量产的智能驾驶系统和软件开发》这一主题进行了直播讲解。本次分享主要分为以下4个部分: 1、智能驾驶…

重读经典(CLIP上):《Learning Transferable Visual Models From Natural Language Supervision》

CLIP 论文逐段精读【论文精读】这一次朱毅博士给大家精读的论文是 CLIP,来自于 OpenAI,是图像文本多模态领域一个里程碑式的工作。 CLIP 的影响力可见一斑,如果按照沐神之前讲的如何判断一个工作的价值来说,CLIP 应该就是 1001001…

TFS准备(一)

一、TFS概念: TFS全称Team FoundationServer,是应用程序生命周期管理的服务端,功能包括如图功能:源代码管理,版本控制,团队开发协作,统一集成,测试管理等。 二、TFS安装要求&#…

重读经典(CLIP下):《Learning Transferable Visual Models From Natural Language Supervision》

上文链接:重读经典(CLIP上):《Learning Transferable Visual Models From Natural Language Supervision》 5. 实验 现在我们已经知道 CLIP 是如何进行预训练的以及作者为什么选用对比学习来预训练 CLIP,接下来我们就…

TFS创建团队项目(三)

打开Visual Studio 2013,视图-团队资源管理器-连接图标(插头图标) 当前是没有TFS服务器,点击服务器按钮 添加,并在URL地址栏里输入装有TFS的服务器IP地址(配置完TFS后有这个URL:http://tfs-serv…

详解4D毫米波雷达数据集(VOD)Multi-class Road User Detection with 3+1D Radar in the View-of-Delft Dataset

Multi-class Road User Detection with 31D Radar in the View-of-Delft Dataset本文介绍一个新的自动驾驶数据集:VOD,论文收录于 ICRA2022。下一代毫米波雷达除了提供距离、方位和多普勒速度外,还会提供高度信息。 在本文中,作者…

自动驾驶之心:毫米波雷达-视觉融合感知方法(前融合/特征级融合/数据级融合)

毫米波雷达-视觉融合感知方法(前融合/特征级融合/数据级融合)分享一个自动驾驶之心的报告:毫米波雷达与视觉融合目标检测。 作者主页为:https://www.zhihu.com/people/nacayu 文章目录1. 毫米波雷达与相机融合检测背景2. 主流融合…

TFS中的迭代(五)

从团队资源管理器中打开迭代选项。 TFS在新建完团队项目后会自动为本团队项目新建迭代子项,包含发布和冲刺。第一级为团队项目TestProject,第二层为发布,第三层为冲刺,这样的层次一共可以建14层。 这些选项可以编辑,添…

2022百度ApolloDay技术开放日:文心大模型在自动驾驶感知中的落地应用

2数据处理大模型技术是自动驾驶行业近年的热议趋势,但能否落地应用、能否用好是关键难题。百度自动驾驶依托文心大模型特色优势,率先实现技术应用突破。百度自动驾驶技术专家王井东表示:文心大模型-图文弱监督预训练模型,背靠文心…