Bootstrap

Java基础--new String()创建了几个对象,String字符串==比较

知识补充
  • 在JDK6之前,字符串常量池存放在永久代;在JDK6之后,字符串常量池存放在Java堆内。
  • 字符串常量池中不会存储相同内容的字符串。
  • intern()方法:如果字符串常量池中没有对应的字符串的话,会先在字符串常量池中生成该字符串,然后返回对象的地址,如果存在对应的字符串,则直接返回字符串常量的地址。
通过字面量创建字符串
String s1 = "Java";
System.out.print(s1.intern()==s1);    //true
  • 执行上述语句时,如果字符串常量池中没有“Java”这个字符串,会在字符串常量池中先创建“Java”字符串对象,然后将s1指向该对象的地址;如果字符串常量池中已经存在“Java”字符串对象,则无需创建对象,直接将s1指向字符串常量池中的对象。
  • s1.intern()也是指向字符串常量池中的对象,所以输出语句输出结果为true。
  • 故上述语句创建0个或者1个对象。
通过new关键字创建字符串
String s2 = new String("Python");
System.out.print(s2.intern()==s2);    //false
  • 执行上述语句时,会先检查字符串常量池存不存在“Python”这个字符串,不存在则在字符串常量池中创建该字符串对象,再去Java堆中创建“Python”字符串对象,并将s2指向堆中对象的地址。
  • s2.intern()也是指向字符串常量池中的对象,所以输出语句输出结果为false。
  • 故上述语句创建1个或者2个对象。
字符串拼接创建字符串
字符串常量的拼接
String s3 = "Er"+"lang";
  • 执行上述语句,jvm编译阶段通过编译器优化后,会把字符串常量直接合并成“Erlang”,相当于 String s3 = “Erlang” 此时若字符串常量池中没有“Erlang”则创建该字符串对象,并将s3指向该对象,若字符串常量池中已经存在“Erlang”,则不创建,直接将s3指向该对象。
  • 故上述语句创建0个或者1个对象。
字符串变量的拼接
String s4 = new String("Go")+new String("lang");
  • 假设字符串常量池中不存在“Go”和“lang”字符串对象。执行该语句,先去字符串常量池中创建“Go”,"lang"两个对象,然后再去Java堆中创建“Go”,“lang”两个对象,使用+号拼接时,内部创建了一个StringBuilder对象,通过append()方法拼接,最后调用StringBuilder的tostring()方法得到一个String对象”Golang“,并把它赋值给s4。
  • 注意此时字符串常量池中并没有“Golang”字符串对象。
  • 故上述语句创建了6个对象(字符串常量池一开始不存在字符串的情况下)。
这时的intern()方法还有点小细节
String s4 = new String("Go")+new String("lang"); //语句1
s4.intern();                                     //语句2
String s5 = "Golang";                            //语句3
System.out.print(s4==s5);  //jdk6返回false,jdk7/8返回true
  • 从上文得知,语句1并没有在字符串常量池中生成”Golang“字符串对象。
    1. 在jdk6版本,执行intern()方法,如果常量池中没有该字符串对象,则会在字符串常量池新建一个字符串对象。此时s5就会指向intern方法生成的这个常量池中的字符串对象,输出语句返回的结果为false。
      图1-jdk6的intern方法
      2.在jdk7/8版本,字符串常量池被转移到了java堆中,执行完intern()方法后, 如果常量池中没有该字符串对象,则会把此对象在堆中的引用地址复制一份,放入字符串常量池中,并返回字符串常量池中的引用地址。此时输出语句返回的结果是true。
      图2-jdk7/8的intern方法
一些字符串”==“比较练习
        /* String 比较 */
		String aa = "abc";
		String bb = new String("abc");
		String cc = "abc";
		String dd = "ab";
		System.out.println(aa == (dd + "c")); // false
		System.out.println(aa == ("ab" + "c")); // true
		System.out.println(aa == cc); // true
		System.out.println(aa == bb); // false
		System.out.println(aa.equals(dd + "c")); // true
		System.out.println("------------------------");
		
		String s1 = "coder";
		String s2 = "coder";
		String s3 = "coder" + s2;
		String s4 = "coder" + "coder";
		String s5 = s1 + s2;
		String s6 = s1 + s1;
		System.out.println(s4 == s5); // false
		System.out.println(s6 == s5); // false
		System.out.println(s3 == s5); // false
		System.out.println(s4 == "codercoder"); // true
		System.out.println(s5 == "codercoder"); // false
		System.out.println(s3 == "codercoder"); // false
打印字符串对象地址的方法
String s1 = "coder";
String s2 = "coder";
String s4 = "coder" + "coder";
String s5 = s1 + s2;
String s6 = s1 + s1;
System.out.println(String.class.getName() + "@" + Integer.toHexString(System.identityHashCode(s4)));
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.class.getName() + "@" + Integer.toHexString(System.identityHashCode(s6)));
System.out.println(String.class.getName() + "@" + Integer.toHexString(System.identityHashCode("codercoder")));

//console:
java.lang.String@1c4af82c
java.lang.String@379619aa
java.lang.String@cac736f
java.lang.String@1c4af82c
;