java堆和栈 常量池_GitHub - han-guang-xue/difference-of-stack-heap-pool: Java中堆、栈和常量池的区别...

Java中堆、栈和常量池的区别

栈 堆 常量池的概念

首先我们先了解一下概念,Java把内存分成两种,一种叫做栈内存,一种叫做堆内存。

栈内存

存放基本类型的变量数据和对象类型的引用(请注意存放的是引用),对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符串常量对象存放在常量池中)

堆内存

堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由java虚拟机自动垃圾回收器来管理

常量池

存放字符串常量和基本类型常量(public static final)

堆栈的比较

一般来说,栈的速度比堆的速度要快,那为什么还要引入堆呢?这就要涉及到堆栈的优缺点了。

栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享(指的是线程共享,而给进程共享)。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。

堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要 在运行时动态分配内存,存取速度较慢。

##奇怪的问题

在学习java堆栈的知识时,也遇到一点有趣的小问题,我很奇怪,查了很多资料后发现有不同的说法。

对于String s=new String("abc");的创建

一种说法:对于通过new产生一个字符串(假设为”abc”)时,会先去常量池中查找是否已经有了”abc”对象,如果已经创建"abc",则不会继续创建。如果没有则在常量池中创建一个此字符串对象,然后堆中再创建一个常量池中此”abc”对象的拷贝对象。一个是编译时决定的,最后放在常量池中。一个是运行时放在堆里面的。

另一种说法:1、首先在堆中(不是常量池)创建一个指定的对象"abc",并让str引用指向该对象 2、在字符串常量池中查看,是否存在内容为"abc"字符串对象 3、若存在,则将new出来的字符串对象与字符串常量池中的对象联系起来 4、若不存在,则在字符串常量池中创建一个内容为"abc"的字符串对象,并将堆中的对象与之联系起来 intern 方法可以返回该字符串在常量池中的对象的引用

String str1 = "abc";

一种说法:

栈中开辟一块空间存放引用str1,

String池中开辟一块空间,存放String常量"abc",

引用str1指向常量池中String常量"abc",

str1所指代的地址即常量"abc"所在地址,输出为true

另一种说法:先在栈中创建一个对String类的对象引用变量str1 ,然后查找栈中有没有存放"abc",如果没有,则将"abc"存放进栈,并令str1 指向"abc",如果已经有"abc",则直接令str1 指向"abc"

对于上述两个问题的两种说法,本人均更倾向于第一种说法,因为第一种说法对程序有优化的作用,第二种说法是多此一举,并未带来任何好处。

讨论:int a=1;那么这个1是存在栈里还是存在常量池?

对于这个问题我也困惑了好久,首先可以肯定的a是int类型的引用,存储在栈里,那么这个1到底是存在哪里呢? 我们通常的理解是1作为一个常量肯定是存储在常量池中啊。在查阅了很多资料后发现,这个1是存储在栈中,并未存储在常量池中。 这里我们需要注意的是对于1我们看起来是常量,但j虚拟机却并不是将其看作是常量而是一个变量,只有声明为final类型的数据JVM才会将其看做是常量,而常量池是存放字符串常量和基本类型常量(public static final)的,所以这里的1是存储在栈里的。

实例分析

我们举一个最常见的例子,分析一下栈基本的处理过程:

int a = 3; int b = 3;

编译器会先处理int a = 3;,首先它会在栈中创建一个变量为a 的引用,然后查找栈中是否有3 这个值,如果没找到,就将3存放进来,然后将a 指向3 。接着处理int b = 3; ,在创建完 b 的引用变量后,因为在栈中已经有3 这个值,便将b 直接指向3 。 这样,就出现了 a 与 b 同时均指向 3 的情况。这时,如果再令 a = 4;,那么编译器会重新搜索栈中是否有 4 这个值,如果没有,就将4 存放进来,并令a 指向 4;如果已经有了,则直接将 a 指向这个地址。 因此a值的改变不会影响到 b 值。 要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况 a 的修改并不会影响到 b,它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

总结以及需要注意的地方

对于字符串:其对象的引用都是存储在栈中的,如果是编译期已经创建好(直接用双引号定义的)的就存储在常量池中,如果是运行期(new出来的)才能确定的就存储在堆中。

对于基本类型应该不会用到常量池,因为基本类型的值就存在栈中,在Java中对基本类型变量的运算、判断以及赋值都是对值的操作,没有对地址操作,例如:int a = 1; int b = 2; a = b; 这是将b的值赋给a,而不是a引用b;

我们在使用诸如String str = "abc";的格式定义类时,总是想当然地认为,我们创建了String类的对象str。请注意,对象可能并没有被创建!唯一可以肯定的是,指向 String类的引用被创建了。至于这个引用到底是否指向了一个新的对象,必须根据上下文来考虑,除非你通过new()方法来显要地创建一个新的对象。因 此,更为准确的说法是,我们创建了一个指向String类的对象的引用变量str,这个对象引用变量指向了某个值为"abc"的String类。

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

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

相关文章

Java当中TreeMap用法

一:引言 当用到了TreeMap时候,是因为要根据键值进行排序,使输出的结果是按递增顺序的 二:上码 package cn.wyj.two;import java.util.Map; import java.util.TreeMap;/*** 一般当 键值需要排序时,我们会选择用 Tree…

redhat java 多个版本_Linux下安装JDK(多个版本) 切换

1、检查系统是否自带了OpenJDK以及相关安装包,如果有的话则应先将其卸载。检查命令:java -versionrpm -qa | grep javarpm -e --nodeps tzdata-java-2013g-1.el6.noarchrpm -e --nodeps java-1.6.0-openjdk-1.6.0.0-1.66.1.13.0.el6.i686rpm -e --nodeps…

efcore 新特性 SaveChanges Events

efcore 新特性 SaveChanges EventsIntro昨天早上看到之前关注的一个 efcore 的 issue 被 closed ,于是看了一眼, ef core 新合并了一个 PR,在 DbContext 中增加了 SaveChanges 相关的几个事件,具体的变更可以参数 PR https://gith…

Java手写HashSet

一&#xff1a;引言 HashSet类继承于 Set接口 其方法均可被直接调用&#xff0c;不用手写&#xff0c;本篇敲的码是为了熟悉底层原理&#xff0c;HashMap的特点&#xff1a;无序&#xff0c;无重复。其底层用的也是map<key,value>容器&#xff0c;但其value值固定,所以在…

十分钟搭建自己的私有NuGet服务器-BaGet

点击上方蓝字"小黑在哪里"关注我吧搭建BaGet上传程序包在vs中使用其他前言NuGet是用于微软.NET&#xff08;包括 .NET Core&#xff09;开发平台的软件包管理器。NuGet能够令你在项目中添加、移除和更新引用的工作变得更加快捷方便。通常使用NuGet都是官方的服务&…

java swing 面试题_下面有关JAVA swing的描述,说法错误的是?

Swing是一个用于开发Java应用程序用户界面的开发工具包。它以抽象窗口工具包(AWT)为基础使跨平台应用程序可以使用任何可插拔的外观风格。Swing开发人员只用很少的代码就可以利用Swing丰富、灵活的功能和模块化组件来创建优雅的用户界面。工具包中所有的包都是以swing作为名称&…

Java当中迭代器的使用(遍历容器ArrayList, HashSet,HashMap)

一&#xff1a;引言 关于entry 的解释代码有注释&#xff0c;觉得挺重要。 二&#xff1a;上码 package cn.wyj.two;import java.util.*; import java.util.Map.Entry;public class Demo10_迭代器的使用 {public static void main(String[] args) {textList();System.out.pr…

mysql or 创建索引_Mysql索引优化

1、单表索引优化单表索引优化分析创建表建表 SQLCREATE TABLE IF NOT EXISTS article(id INT(10) UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,author_id INT(10) UNSIGNED NOT NULL,category_id INT(10) UNSIGNED NOT NULL,views INT(10) UNSIGNED NOT NULL,comments INT(1…

.Net Core HttpClient处理响应压缩

前言在上篇文章[ASP.NET Core中的响应压缩]中我们谈到了在ASP.NET Core服务端处理关于响应压缩的请求&#xff0c;服务端的主要工作就是根据Content-Encoding头信息判断采用哪种方式压缩并返回。之前在群里有人问道过&#xff0c;现在的网络带宽这么高了还有必要在服务端针对请…

Java容器的遍历之增强for循环

一&#xff1a;为什么要用增强版的 for 循环呢 在普通的数组遍历当中&#xff0c;我们采用普通的for循环即可&#xff0c;但在遍历2.遍历集合、容器&#xff0c;当中我们一般采用增强版的for循环 &#xff0c;简单方便。 二&#xff1a;构造模式 for(数据类型 变量&#xff…

mysql脚本的制作_制作脚本实现mysql自动备份

首先执行vi dbbackup.sh命令&#xff0c;在打开的编辑器输入&#xff1a;#!/bin/bash/usr/local/mysql/bin/mysqldump -uuser -ppasswd databasename > /home/wwwroot/backup/date_$(date%Y%m%d).sql这段命令的意思是&#xff1a;用mysqldump导出名为databasename的数据库到…

在 PostgreSQL 中使用码农很忙 IP 地址数据库

在下载到码农很忙 IP 地址数据库后&#xff0c;我们可以将其存储在 PostgreSQL 数据库中&#xff0c;并在需要查询某个 IP 对应的位置数据时&#xff0c;通过 SQL 语句获取正确的结果。这是一种很便捷的使用方式&#xff0c;并且在增加了恰当的索引后&#xff0c;可以取得不错的…

Java当中Collections的用法

一&#xff1a;上码 package cn.wyj.two;/*** Collections辅助类的使用* * author 王永杰**/ import java.util.*;public class Demo11_Collections辅助类 {public static void main(String[] args) {List<String> list new ArrayList<String>();for( int i 0; …

.NET开发者提高编程技能的5种方法

.NET开发者提高编程技能的5种方法https://insights.dice.com/2017/08/29/5-ways-improve-programming-skills/即使拥有40年的编程经验&#xff0c;我唯一能确定的就是肯定有比我更好的程序员。但是我并没有放弃&#xff0c;我会继续尝试并提高自己的编程技能。我认为有五件事可…

Java当中用 javabean和其他容器存入表格数据 或 利用 容器进行存储表格

一&#xff1a;javabean 和list容器或map容器 package cn.wyj.two;import java.util.*;/*** javabean :必须有一个无参构造函数&#xff1b;变量属性私有化&#xff1b;* 本篇还是打印一张表* author 86155**/ public class Demo13_Javabean和其他容器 {public static void ma…

7-25 朋友圈 (25 分)(详解+并查集的了解和应用)

一&#xff1a;题目 某学校有N个学生&#xff0c;形成M个俱乐部。每个俱乐部里的学生有着一定相似的兴趣爱好&#xff0c;形成一个朋友圈。一个学生可以同时属于若干个不同的俱乐部。根据“我的朋友的朋友也是我的朋友”这个推论可以得出&#xff0c;如果A和B是朋友&#xff0…

使用Azure人脸API对图片进行人脸识别

人脸识别是人工智能机器学习比较成熟的一个领域。人脸识别已经应用到了很多生产场景。比如生物认证&#xff0c;人脸考勤&#xff0c;人流监控等场景。对于很多中小功能由于技术门槛问题很难自己实现人脸识别的算法。Azure人脸API对人脸识别机器学习算法进行封装提供REST API跟…

java while do循环_c语言中,while 和 do while 循环的主要区别是( )

1、循环构造的表达式不同&#xff1a;while循环构造的表达式为&#xff1a;while(表达式)&#xff5b;循环体&#xff5d;。do&#xff0d;while循环构造表达式为&#xff1a;do&#xff5b;循环体&#xff1b;&#xff5d;while(条件表达)&#xff1b;。2、执行末尾循环体的次…

Java当中 IO(File) 操作 之 递归打印子孙级目录和文件名称

一&#xff1a;上码 package com.wyj.one;import java.io.File;/*** 列出下一级&#xff1a;* 1, list(): 列出下一级名称* 2&#xff0c; listFiles()&#xff1a;列出下一级File对象* 3, listRoots():列出盘符* author 86155**/ public class Demo8_列出下一级 {/*** p…

[NewLife.Net]单机400万长连接压力测试

目标对网络库NewLife.Net进行单机百万级长连接测试&#xff0c;并持续收发数据&#xff0c;检测网络库稳定性。【2020年8月1日晚上22点】先上源码&#xff1a;https://github.com/NewLifeX/NewLife.Net结论&#xff0c;8月1日晚达到200万&#xff0c;8月2日下午达到404万。上一…