对于创建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对象机制 字符串缓冲池 字符串拼接机制的更多相关文章

  1. java 创建string对象机制 字符串缓冲池 字符串拼接机制 字符串中intern()方法

    字符串常量池:字符串常量池在方法区中 为了优化空间,为了减少在JVM中创建的字符串的数量,字符串类维护了一个字符串池,每当代码创建字符串常量时,JVM会首先检查字符串常量池.如果字符串已经存在池中,就 ...

  2. Java中String对象创建机制详解()

    一String 使用 private final char value来实现字符串存储 二Java中String的创建方法四种 三在深入了解String创建机制之前要先了解一个重要概念常量池Const ...

  3. Java 关于创建String对象过程的内存分配

    一.String s = "abc"  和 String s = new String("abc") 的区别 1.String s = "abc&qu ...

  4. java笔试中创建String对象的思考

    题目是这样的下面那些生成新的String对象() A . String  s = new String(); B . String  s = new String("A"); C. ...

  5. 创建String对象过程的内存分配

      转载自  https://blog.csdn.net/xiabing082/article/details/49759071       常量池(Constant Pool):指的是在编译期被确定 ...

  6. Java:String对象小记

    Java:String对象小记 对 Java 中的 String 对象,做一个微不足道的小小小小记 字节和字符的区别 字节 byte: 一个字节包含8个位(bit),因此byte的取值范围为-128~ ...

  7. 【Java】Java创建String时,什么情况放进String Pool?

    对Java创建String是否放入String pool作代码性的试验. 参考的优秀文章 JAVA面试题解惑系列(二)——到底创建了几个String对象? public String(String o ...

  8. Java中String对象的不可变性

    首先看一个程序 package reverse; public class Reverse { public static void main(String[] args) { String c1=n ...

  9. java 创建匿名对象及声明map list时初始化

    java 创建匿名对象 类似于c# 中的 new { a:"aaa",b:"bbb"}; 1 创建匿名对象Object myobj = new Object() ...

随机推荐

  1. PHP 检测变量是否为空

    PHP 中以下值得计算结果为 false: 关键字 boolean false 整型 integer 0 浮点型 double 0.0 字符串 string ""  字符串 str ...

  2. [转载] Win PE内安装Windows 7原版镜像 / 安装程序无法创建新的系统分区,也无法定位现有的系统分区

    格式化C盘为NTFS格式 解压ISO安装文件中找到BOOT.BOOTMGR和SOURCES这三个文件到C盘根目录下:或者复制BOOT.BOOTMGR,在C盘新建文件夹SOURCES,复制ISO安装文件 ...

  3. 美萍超市销售管理系统标准版access数据库密码mp611

    美萍超市销售管理系统标准版access数据库密码mp611 作者:admin  来源:本站  发表时间:2015-10-14 19:01:43  点击:199 美萍超市销售管理系统标准版access后 ...

  4. 掌握Thinkphp3.2.0----SQL查询

    首先,先谈一下对查询的理解:查询的对象是数据库中的数据表,一个或多个:查询的限制就是各种条件或要求:查询的结果=表对象+限制(条件). 对数据表的操作(CRUD)查询是最复杂也是最关键的一步!'SEL ...

  5. JAVA基础篇NO1--环境变量的配置及命名规则

    标签(空格分隔): java基础 一:计算机概述 计算机:硬件和软件 硬件:控制器 运算器 存储器 输入和输出设备       存储器:外存(硬盘) 内存 软件:系统软件 应用软件   系统软件:wi ...

  6. win7 将所有 视图 改为 '详细信息'

    1.随便进入某个文件夹->(菜单栏中)查看->选'详细信息' 2.(菜单栏中)工具->文件夹选项->查看->'应用到文件夹'

  7. Theos 工程

    一.tweak 工程 1.创建步骤 a) terminal cd 到想要存放项目的目录下 b) 按图步骤完成即可 二.工程文件描述 1.control 记录 deb 包管理系统所需的基本信息. 2.a ...

  8. java中类继承,到底继承了什么?

    继承的最大好处就是为了实现代码的复用.那么,子类到底从父类得到的什么呢? 实例成员 父类的private成员不会被子类继承,子类不能访问.但是子类对象的确包含父类的私有成员. 父类的 包访问成员 继承 ...

  9. 笔记 .Net反射机制

    .Net中反射机制, 一般常用的就是这两句: Type type=Assembly.Load("RoadFlow.Data."+dataType).GetType(typeName ...

  10. JMeter学习-024-JMeter 命令行(非GUI)模式详解(二)-执行代理设置

    闲话少述,接 上文 继续... 5.设置代理 jmeter -n -t JMeter分布式测试示例.jmx -H 20.9.215.90 -P 9999 -l report\01-result.csv ...