你可能不知道的秘密——String s=new String(“abc”)到底创建了几个对象?
String s=new String(“abc”)创建了几个对象?
在探讨上述问题结论之前,我们需要了解常量池这个概念。
常量池
由于字符串在Java中被大量使用,为了避免每次都创建相同的字符串对象(这样就意味着占据更多内存),JVM对字符串对象做了一定的优化,有一块专门的区域来存储字符串常量,该区域就是字符串常量池。常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。
需要注意的是:
在JDK1.6即以前,常量池位于JVM的方法区中。
在JDK7即以后,常量池放在堆中。
官网说明:
Synopsis: In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences.
理解字符串常量池的概念后,我们来看一下代码:
public class StringDemo {
public static void main(String[] args) {
String str1 = "abc";
String str2 = "abc";
String str3 = new String("abc");
System.out.println(str1==str2); //第七行
System.out.println(str2==str3);//第八行
}
}
你看到上述代码,预测一下控制台输出!
第7行输出true,第8行输出false。
执行过程:
执行String str1 = “abc”;
时,JVM常量池中并没有"abc"这个字符串,此时会在常量池中创建这个对象,然后将引用赋给str1`。执行
String str2 = "abc";时,JVM在常量池中找到"abc"这个字符串了,所以直接将应用附给它。执行
String str3 = new String("abc");时,JVM会在堆中创建一个String对象,然后将传进去的常量池String对象中保存的char[]数组,赋给堆中的String。/**
String类的部分源代码
**/
/** The value is used for character storage. */
private final char value[]; /** Cache the hash code for the string */
private int hash; // Default to 0 public String(String original) {//String的构造器
this.value = original.value;
this.hash = original.hash;
}
回到最初的问题,String s=new String(“abc”)到底创建了几个对象?
如果在执行String s=new String(“abc”)这句话之前,常量池中并没有"abc",那么在创建new String()时会先在常量池中 创建字符串常量,然后通过这个字符串常量,在堆中创建一个新的字符串,但是这两个字符串对象(常量池中的"abc"和堆中的"abc")底层保存字符的数组都是一个。
如果在执行之前就有了"abc"这个字符串常量了(例如上面的代码),在执行String s=new String(“abc”)这句话时,也就只在堆中创建一个对象了。
验证常量池中的"abc"和堆中的"abc"底层保存字符的数组都是一个
前面我们查看String的构造器后得出结论,采用new关键字在堆中创建的"abc"和常量池中"abc"虽然对象不是一个,但是它们两个对象底层指向的数组是一个,那我们就通过代码验证这个结论。
整体思路是这样的:我们通过反射,修改常量词中字符串对象底层数组的值,看堆中的String对象的值是否跟着改变:
@Test
public void test() throws Exception {
//在常量池中创建一个"abc"
String str = "abc";
//通过常量词中的"abc"在堆中创建一个String对象
String str2 = new String("abc");
//获取String类中的value字段
Field field = String.class.getDeclaredField("value");
//将字段设置为可访问的
field.setAccessible(true);
//获取str对象上的value属性的值
char[] arr = (char[]) field.get(str);
arr[2]='1';
System.out.println(str);//输出:ab1
System.out.println(str2);//输出:ab1
}
你可能不知道的秘密——String s=new String(“abc”)到底创建了几个对象?的更多相关文章
- new String("ab")到底创建了几个对象说明
new String("ab")到底创建了几个对象? 之前一直被这个问题困扰,网上一些描述的都不是很清楚,自己看了一些资料可算搞清楚了,那就在博客上记录一下吧! String st ...
- String,你到底创建了几个对象????
String str=new String("aaa"); 这行代码究竟创建了几个String对象呢?答案是2个,而不是3个.由于 new String("aaa&quo ...
- String s="a"+"b"+"c"+"d";创建了几个对象?
对于如下代码: package reviewTest; /** * @ClassName: StringTest * @Description: 测试String的字符串相加优化 * @author ...
- String,到底创建了多少个对象?
String str=new String("aaa"); <span style="font-size:14px;">String str=n ...
- String s="a"+"b"+"c",到底创建了几个对象?
首先看一下这道常见的面试题,下面代码中,会创建几个字符串对象? String s="a"+"b"+"c"; 如果你比较一下Java源代码和反 ...
- Java String Pool--String s = new String("a") 到底创建了几个对象?
本篇重点(tips): 1. String Pool 是以Java 中 String 对象是不可变的这一特性为基础的 2. String Pool是Heap(堆)中的一块特殊空间(JDK 1.7 之前 ...
- POLARDB · 最佳实践 · POLARDB不得不知道的秘密(二)
前言 POLARDB For MySQL(下文简称POLARDB)目前是阿里云数据库团队主推的关系型数据库.线上已经有很多企业用户在使用并且稳定运行了很久.当然,由于POLARDB是为云上环境专门打造 ...
- POLARDB · 最佳实践 · POLARDB不得不知道的秘密
## 前言 POLARDB作为阿里云下一代关系型云数据库,自去年9月份公测以来,收到了不少客户的重点关注,今年5月份商业化后,许多大客户开始陆续迁移业务到POLARDB上,但是由于POLARDB的很多 ...
- new String创建了几个对象
String str = new String(“abc”) 到底创建了几个对象? 首先String str是定义了一个字符串变量,并未产生对象,=不产生对象,那么只有后面的new String(& ...
- 工作10年后,再看String s = new String("xyz") 创建了几个对象?
这个问题相信每个学习java的同学都不陌生,作为一个经典的面试题,到现在工作这么多年了我真是认为挺操蛋的一个问题,在网上到现在你仍然可以看见很多讨论这个问题的人,其中不乏工作很多年的人都有争论,我认为 ...
随机推荐
- abcde =(ab+cd)的平方
int i, a, b; for (i = 1000; i < 10000; i++) { a = i / 100; b = i % 100; if ((a + b) * (a + b) == ...
- openGauss系统函数添加指导
openGauss 系统函数添加指导 1.函数架构简介 openGauss 内函数的可以分为两个部分: 身份注册声明:openGauss 中存在一个系统表 pg_proc,这个表存放了所有函数的基 ...
- DevEco Device Tool 3.1 Release新版本发布,新增资源管理器、SFTP、HDC
原文链接:https://mp.weixin.qq.com/s/UGBirjf8nBjnfKck9TlyWg,点击链接查看更多技术内容: DevEco Device Tool是面向智能设备开发者 ...
- HarmonyOS音频开发指导:使用OpenSL ES开发音频播放功能
OpenSL ES全称为Open Sound Library for Embedded Systems,是一个嵌入式.跨平台.免费的音频处理库.为嵌入式移动多媒体设备上的应用开发者提供标准化.高性 ...
- HDC2021技术分论坛:HarmonyOS本地模拟器重磅来袭!
作者:longjiangyun,模拟器开发工程师 HarmonyOS模拟器是应用开发者使用IDE进行代码开发.调试.测试等活动中必不可少的工具,它分为本地模拟器和远程模拟器,其中远程模拟器又分为单设备 ...
- 报名直达丨HarmonyOS开发者创新大赛线下城市交流会来了,约吗?
HarmonyOS开发者创新大赛线下城市交流会 正式开启啦! 在这里,将有专业的讲师 与HarmonyOS开发者们面对面演示开发实操.交流开发心得 还等什么?赶快扫码报名吧~↓↓↓ 城市交流会报名链接 ...
- Maven 必备技能:MAC 系统下 JDK和Maven 安装及环境变量配置详细讲解
开发中难免因系统问题或者版本变更反复折腾JDK和Maven环境变量,干脆写个笔记备忘个,也方便小伙伴们节省时间. =================JDK安装与环境变量配置====== 1.官网下载j ...
- 从零开始写 Docker(十一)---实现 mydocker exec 进入容器内部
本文为从零开始写 Docker 系列第十一篇,实现类似 docker exec 的功能,使得我们能够进入到指定容器内部. 完整代码见:https://github.com/lixd/mydocker ...
- Django框架——路由分发、名称空间、虚拟环境、视图层三板斧、JsonResponse对象、request获取文件、FBV与CBV、CBV源码剖析、模版层
路由分发 # Django支持每个应用都可以有自己独立的路由层.静态文件.模版层.基于该特性多人开发项目就可以完全解耦合,之后利用路由分发还可以整合到一起 多个应用都有很多路由与视图函数的对应关系 这 ...
- 【笔记】greatest/least函数&Round函数
刷了一下力扣,发现有很多的函数是自己不清楚的,用了这些函数是比较容易得出结果的,不用自己费心去实现一些奇怪的东西 1.最大最小值 链接:https://leetcode.cn/problems/num ...