String Table

不可变性

  String 在jdk8中 是 char value[];jdk9中式byte[] 更加节约内存空间。String 代表不可变的字符序列,对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值。

/**
 * String代表不可变的字符序列,拥有不可变性。对字符串重新赋值的时候,需要重新指定内存
 */
public class A2 {

    String str = new String("good");
    char[] ch = {'t', 'e', 's', 't'};

    public void change(String str, char ch[]) {
        System.out.println("======================");
        System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(str)));
        str = "test ok";        // 这不会改变实例变量的值
        //this.str = "test ok"; // 这样就真正修改了实例变量
        ch[0] = 'b';
        System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(str)));
        System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(str)));
        System.out.println("======================");
    }

    public static void main(String[] args) {
        A2 ex = new A2();
        ex.change(ex.str, ex.ch);
        System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(ex.str)));
        System.out.println(ex.str);//good
        System.out.println(ex.ch);//best
    }
}

字符串常量池

  通过 new String("str") 的方式创建对象,它是存在堆中的。而我们通过字面量的方式给一个字符串赋值,它是放在字符串常量池中的。

public static void main(String[] args) {
    String s1 = "wulei"; // wulei 是字符串常量池,它是放在堆中的
    String s2 = "wulei"; // 字符串常量池中是没有相同的字符串的,这两个wulei其实是同一个
    System.out.println(s1==s2);         // 判断内存地址 true
    System.out.println(s1.equals(s2));  // 比较数据的值,这个不用看肯定是true
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s1)));
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s2)));
}

  

内存分布

public static void main(String[] args) {
    int i = 1;
    Object obj = new Object();
    A3 mem = new A3();
    mem.foo(obj);
}

private void foo(Object param) {
    String str = param.toString();
    System.out.println(str);
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(str)));
}

  

创建对象

/**
 * 创建了几个对象
 */
public class A4 {

    public static void main(String[] args) {
        // 一个对象是:new关键字在堆空间创建的
        // 另一个对象是:字符串常量池中的对象"ab"。 字节码指令:ldc
        String s1 = new String("ab");

        // 对象1: new String("a")
        // 对象2: 常量池中的"a"
        // 对象3: new String("b")
        // 对象4: 常量池中的"b"
        // 对象5: + 等于 new StringBuilder()
        // 对象6: 最后返回字符串,等于 StringBuilder.toString()
        /*
            如下的s1 + s2 的执行细节:(变量s是我临时定义的)
            ① StringBuilder s = new StringBuilder();
            ② s.append("a")
            ③ s.append("b")
            ④ s.toString()  --> 约等于 new String("ab"),具体的内容为拼接的结果:javaEEhadoop

            在jdk5.0之后使用的是StringBuilder,在jdk5.0之前使用的是StringBuffer
         */
        String s2 = new String("a") + new String("b");
    }
}

字符串拼接

public static void main(String[] args) {
    /*
        编译期优化
            String s4 = "javaEE" + "hadoop"; 在编译时会被替换为 String s4 = "javaEEhadoop";
     */
    String s1 = "javaEE";
    String s2 = "hadoop";

    String s3 = "javaEEhadoop";
    String s4 = "javaEE" + "hadoop";

    System.out.println(s3 == s4);//true
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s3)));
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s4)));
    System.out.println("=====================");

    /*
    如下的s1 + s2 的执行细节:(变量s是我临时定义的)
        ① StringBuilder s = new StringBuilder();
        ② s.append("a")
        ③ s.append("b")
        ④ s.toString()  --> 约等于 new String("ab"),具体的内容为拼接的结果:javaEEhadoop
     */
    String s5 = s1 + "hadoop";
    String s6 = s1 + s2;
    System.out.println(s3 == s5);//false
    System.out.println(s3 == s6);//false
    System.out.println(s5 == s6);//false
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s5)));
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s6)));
    System.out.println("=====================");

    /*
        如果拼接符号左右两边都是字符串常量或常量引用,则仍然使用编译期优化,即非StringBuilder的方式。
     */
    final String a1 = "a";
    final String a2 = "b";
    String a3 = "ab";
    String a4 = a1 + a2;
    System.out.println(a3 == a4);//true
}

intern()

public static void main(String[] args) {
    String s1 = "javaEEhadoop";
    String s2 = new String("javaEEhadoop");
    System.out.println(s1==s2);//false
    /*
        intern():
                首先,会判断堆中是否有字符串String("javaEEhadoop"), 有的话,就不会在字符串常量池创建 "javaEEhadoop"了,
                    而是在串池里面存指向String("javaEEhadoop")的地址,并返回此对象的地址。
                然后,会判断串池中是否已经有"javaEEhadoop"了,有的话就直接指向之前的"javaEEhadoop",并返回此对象的地址。
                最后,以上要是都没有,就会在串池中创建一个"javaEEhadoop",并返回此对象的地址。

         扩展:
               String a = new String("ss")+new String("bb");
               a.intern();        // 串池里面保存了new String("ssbb")引用
               String b = "ssbb"; // 由于串池有引用了,就不会创建了,此时b==a。要是没有执行a.intern(),则会新创建对象
     */
    String s3 = s2.intern();
    System.out.println(s1 == s3);//true
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s1)));
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s2)));
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s3)));
    System.out.println("=====================");


    String s4 = new String("javaEE");
    String s5 = s4.intern();
    System.out.println(s4 == s5);//false
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s4)));
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(s5)));
    System.out.println("=====================");

    String b = new String("a") + new String("b");//new String("ab")
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(b)));
    //在上b一行代码执行完以后,字符串常量池中并没有"ab"
    String b2 = b.intern();//jdk6中:在串池中创建一个字符串"ab"b
    //jdk8中:串池中没有创建字符串"ab",而是创建一个引用,指向
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(b)));
    //由于b.intern()的时候, 已经在串池指向堆的new String("ab")了,所以这里的"ab"不会创建新对象,而是之前的地址
    String x = "ab";//指向b2
    System.out.println(b2 == "ab");//true
    System.out.println(b == "ab"); //true
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(b2)));
    System.out.println(b == x);    //true
    System.out.println(String.class.getName()+"@"+Integer.toHexString(System.identityHashCode(x)));
    System.out.println("=====================");


    String c1 = new String("cd");//执行完以后,会在字符串常量池中会生成"cd",堆里也一个new String("cd")
    String c2 = c1.intern();//指向串池
    String c3 = "cd";       //指向串池的c2
    System.out.println(c1 == c2);//false
    System.out.println(c3 == c2);//true
    System.out.println("=====================");

    String e1 = new String("e") + new String("f");////执行完以后,不会在字符串常量池中会生成"ef"
    String e2 = e1.intern();//
    String e3 = "ef";//指向e2
    System.out.println(e1 == e2);//true
    System.out.println(e3 == e2);//true
    System.out.println("=====================");
    String e11 = new String("e") + new String("f");////执行完以后,不会在字符串常量池中会生成"ef"
    String e31 = "ef";//由于堆中有了一个new String("ef")了,没必要在字符串常量池创建"ef", 直接在字符串常量池存一个地址指向堆的new String("ef")就好了
    String e21 = e1.intern();//指向e31
    System.out.println(e11 == e21);//false
    System.out.println(e31 == e21);//true
    System.out.println("=====================");

    String g = new String("1");
    String g3 = g.intern();//调用此方法之前,字符串常量池中已经存在了"1",
    String g2 = "1";//指向g3
    System.out.println(g == g2);//false
    System.out.println(g == g3);//false
    System.out.println(g2 == g3);//true
    System.out.println("=====================");

    String h3 = new String("3") + new String("3");//new String("33")
    //执行完上一行代码以后,字符串常量池中,是否存在"33"呢?答案:不存在!!
    String h4 = "33";//在字符串常量池中生成对象"33"
    String h5 = h3.intern();//指向h4
    System.out.println(h3 == h4);//false
    System.out.println(h5 == h4);//true
}

 

posted @ 2022-10-25 15:44  吴磊的  阅读(61)  评论(0编辑  收藏  举报
//生成目录索引列表