java 创建string对象机制 字符串缓冲池 字符串拼接机制
对于创建String对象的机制,在这一过程中涉及的东西还是值得探究一番的。
首先看通过new String对象和直接赋值的方式有什么区别,看如下代码:
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = "abc";
String str3 = new String("abc");
String str4 = "abc";
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str2 == str3);
System.out.println(str2 == str4);
}
结果是:false false false true
我们知道 == 比较的是对象的引用,从代码以及结果可以看出来这段程序中只有三个对象,str1指向一个对象,str3指向一个对象,str2和str4共同指向一个对象。可是到这里有的同学就会迷惑了,我们知道在java中String类是被final修饰的是不可改变的应该每次都会重新生成一个对象啊。可是在这里对象内容都是"abc",所以程序本身也没有发生改变。如果发生改变也不一定会重新生成对象。这都和string机制中的字符串缓冲池有关系。
当用new的方法创建一个string对象时会先在字符串缓冲池中找有没有和新创建的字符串内容相等的对象,如果没有的话就会在缓冲池新创建一个字符串对象然后再在堆中创建字符串对象,如果缓冲池中已经有了和新创建的字符串内容相等的对象就会直接在堆上新创建对象。如果不用new的方式也是先会看缓冲池中有没有创建过这个对象,如果没有创建就在里边创建一个,如果已经创建了 那新声明的引用就会直接指向这个对象。
所以main方法的第一行是执行的时候发现缓冲池中并没有一个内容是"abc"的对象所以先在缓冲池中为创建了一个对象内容是"abc",然后在堆中又创建了一个对象。执行到第二行的时候依然会想去缓冲池中找有没有内容是"abc"的字符串对象,发现已经有了。因为他不用在堆上创建对象所以直接把str2指向缓冲池中的对象。第三行一样的道理缓冲池中已经有了所以直接在堆上新建一个就好了。第四行和第二行一样。所以就出现了false false false true的结果。
再用一段代码验证一下:
public static void main(String[] args) {
String str1 = new String("abc");
String str2 = "abc";
String str3 = new String("abc");
System.out.println(str1 == str2.intern());
System.out.println(str1 == str3.intern());
System.out.println(str2 == str3.intern());
System.out.println(str2 == str1.intern());
}
结果:false false true true
首先intern()方法:
public String intern()返回字符串对象的规范化表示形式。(这句话到底啥意思我也不太清楚)
当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(该对象由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并且返回此 String 对象的引用。 它遵循对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
也就是说intern()方法返回的字符串对象肯定是池中的对象而且字符串内容和调用该方法的对象的内容一样。那么结果是false false true true也就不难理解了。str3.intern()和str1.intern()返回的对象就是str2所指向的对象呀。所以我们的结论也得以验证。
在补充一点关于字符串拼接时的情况:
public static void main(String[] args) {
String str1 = "abcd";
String str2 = "ab";
String str3 = "cd";
String str4 = str2 + str3;
String str5 = "ab" + "cd";
System.out.println(str1 == str4);
System.out.println(str1 == str5);
}
结果:false true
这时可能就又会迷惑了,哈哈。这就是程序有意思的地方。
首先说第一个结果是false。str4所指向的对象不应该是缓冲池中的对象吗?讲道理应该是返回true的呀。这就又涉及到字符串拼接的机制了。原来两个字符串str1, str2的拼接首先会调用 String.valueOf(obj),这个Obj为str1,而String.valueOf(Obj)中的实现是return obj == null ? "null" : obj.toString(), 然后产生StringBuilder, 调用的StringBuilder(str1)构造方法, 把StringBuilder初始化,长度为str1.length()+16。此时的StringBuilder对象是在堆上创建的!, 接下来调用StringBuilder.append(str2), 把第二个字符串拼接进去, 然后调用StringBuilder.toString返回结果。所以会返回false。
而对于第二个结果来说这种拼接方式,jvm会直接把"ab" + "cd" 看成"abcd"。实际上jvm对于这时候的 + (加号)的处理是在编译期就已经完成了。这时候并没有涉及到stringbuilder。
java 创建string对象机制 字符串缓冲池 字符串拼接机制的更多相关文章
- java 创建string对象机制 字符串缓冲池 字符串拼接机制 字符串中intern()方法
字符串常量池:字符串常量池在方法区中 为了优化空间,为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池.如果字符串已经存在池中,就 ...
- Java中String对象创建机制详解()
一String 使用 private final char value来实现字符串存储 二Java中String的创建方法四种 三在深入了解String创建机制之前要先了解一个重要概念常量池Const ...
- Java 关于创建String对象过程的内存分配
一.String s = "abc" 和 String s = new String("abc") 的区别 1.String s = "abc&qu ...
- java笔试中创建String对象的思考
题目是这样的下面那些生成新的String对象() A . String s = new String(); B . String s = new String("A"); C. ...
- 创建String对象过程的内存分配
转载自 https://blog.csdn.net/xiabing082/article/details/49759071 常量池(Constant Pool):指的是在编译期被确定 ...
- Java:String对象小记
Java:String对象小记 对 Java 中的 String 对象,做一个微不足道的小小小小记 字节和字符的区别 字节 byte: 一个字节包含8个位(bit),因此byte的取值范围为-128~ ...
- 【Java】Java创建String时,什么情况放进String Pool?
对Java创建String是否放入String pool作代码性的试验. 参考的优秀文章 JAVA面试题解惑系列(二)——到底创建了几个String对象? public String(String o ...
- Java中String对象的不可变性
首先看一个程序 package reverse; public class Reverse { public static void main(String[] args) { String c1=n ...
- java 创建匿名对象及声明map list时初始化
java 创建匿名对象 类似于c# 中的 new { a:"aaa",b:"bbb"}; 1 创建匿名对象Object myobj = new Object() ...
随机推荐
- DevOps is dirty work - What's the deal
什么是DevOps?终于又回到这个最初的问题. 第一次看到这个词的时候,还身陷于各种敏捷概念轰炸中.用“身陷”这个词其实并不准确,因为那个年代的我也是那些热情洋溢地无处不宣传敏捷的热血文艺青年中的一员 ...
- 关于Hibernate 5 和 Hibernate 4 在创建SessionFactory的不同点分析(解决 org.hibernate.MappingException: Unknown entity: xx类报错问题)
Hibernate4版本的SessionFactory实例构建的步骤是这样的(也是很多学习资料的通用范本): //Configuration就是代表着hibernate的那个xml配置文件对象,如果c ...
- QFileSystemModel
#include "dialog.h" #include "ui_dialog.h" Dialog::Dialog(QWidget *parent) : QDi ...
- 毕业设计 之 二 PHP学习笔记(一)
毕业设计 之 二 PHP学习笔记(一) 作者:20135216 平台:windows10 软件:XAMPP,DreamWeaver 一.环境搭建 1.XAMPP下载安装 XAMPP是PHP.MySQL ...
- Ubuntu上安装Karma失败对策
在Ubuntu上安装Karma遇到超时 timeout 错误.Google了一下,国外的码农给了一个快捷的解决方案,实测可行,贴在这里: sudo apt-get install npm nodejs ...
- 【OpenWRT】【RT5350】【二】烧写OpenWrt到RT5350开发板
烧写bin文件到开发板的方式有很多种,我采用的是通过web页面直接上传文件的方式 首先通过浏览器登陆路由器(192.168.1.1),作者的开发板已经烧好了OpenWrt并且可以通过Luci登陆,所以 ...
- imx6 uboot saveenv fail
uboot设置环境变量之后,不能保存在EMMC中,出现错误. MX6SDL SABRESD U-Boot > saveenv Saving Environment to SPI Flash... ...
- swift:谈谈swift几种常见属性的区别
一.前奏 Swift作为一门新语言,经过几年的发展,逐渐趋于完善,目前已经更新到3.0版本,它汇集许多其他语言的特点,例如JS.Paython.C++等,完全区别于OC.个人感觉它没有完全的OOP和O ...
- Linux下查看某进程相关进程
1- ps -T <pid> ###pid表示进程号 或者ps -T -p <pid> 2- top -H -p <pid> ###pid表示进程号 3- ...
- 基于 debootstrap 和 busybox 构建 mini ubuntu
基于 debootstrap 和 busybox 构建 mini ubuntu 最近的工作涉及到服务器自动安装和网络部署操作系统,然后使用 ansible 和 saltsatck 进行配置并安装 op ...