对于创建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. js 滚动的文字(走马灯)

    // 滚动的文字 function marqueeScroll() { //var $target = $(".marquee_outer:visible"); if($(&quo ...

  2. Python 打包工具cx_freeze 问题记录及解决办法

    在节前的最后一天,解决了打包过程中遇到的所有问题,可以成功运行了!真是个好彩头,希望新的一年一切顺利! 以下是在使用cx_freeze过程中遇到的问题及解决办法(Win7) 问题描述:运行exe,启动 ...

  3. Immutable api example

    var temp=[{name:"kitty",age:31},{name:"ff",age:22},{name:"kitty",age:4 ...

  4. Redis性能测试

    Redis 性能测试 Redis 性能测试是通过同时执行多个命令实现的.Redis性能测试主要是通过src文件夹下的redis-benchmark来实现(Linux系统下) 语法 redis 性能测试 ...

  5. .net DropDownList静态联动

    1.前台 <span id="spnClient" style="margin-left: 30px; margin-top: 10px"> < ...

  6. node.js事件轮询(1)

    事件轮询(引用) 事件轮询是node的核心内容.一个系统(或者说一个程序)中必须至少包含一个大的循环结构(我称之为"泵"),它是维持系统持续运行的前提.nodejs中一样包含这样的 ...

  7. Linux CentOS 中安装 MySql

    CentOS7的yum源中默认好像是没有mysql的.为了解决这个问题,我们要先下载mysql的repo源. 1. 下载mysql的repo源 $ wget http://repo.mysql.com ...

  8. ADSL自动更换IP地址源代码

    有些网站限制IP地址,什么一个IP地址只能一次之类的.特别是投票网址,为了防止刷票,限制1个IP只允许投票一次! 此程序采用Vs2010+C#开发,提供全部源代码!方便程序猿朋友二次开发! 可以后台运 ...

  9. TIJ——Chapter Seven:Reusing Classes

    Reusing Classes 有两种常用方式实现类的重用,组件(在新类中创建存在类的对象)和继承. Composition syntax Every non-primitive object has ...

  10. 接口测试(二)—HttpClient

    使用HttpClient进行接口测试,所需要使用的相关代码 HttpClient进行接口测试所需jar包:httpclient.jar.httpcore.jar.commons-logging.jar ...