public final class String
private final char value[];
jdk9private final byte[] value;
private final char value[];
存储字符,jdk9=+使用private final byte[] value; private final byte coder;
存储字符public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[]; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L;
public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** * The value is used for character storage. * * @implNote This field is trusted by the VM, and is a subject to * constant folding if String instance is constant. Overwriting this * field after construction will cause problems. * * Additionally, it is marked with {@link Stable} to trust the contents * of the array. No other facility in JDK provides this functionality (yet). * {@link Stable} is safe here, because value is never null. */ @Stable private final byte[] value; /** * The identifier of the encoding used to encode the bytes in * {@code value}. The supported values in this implementation are * * LATIN1 * UTF16 * * @implNote This field is trusted by the VM, and is a subject to * constant folding if String instance is constant. Overwriting this * field after construction will cause problems. */ private final byte coder; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L;
总述
public final class String
private final char value[];
jdk9private final byte[] value;
代码
package xcrj; /* * String不可变性 * 结果 * 1处hashcode=2处hashcode=3处的hashcode * */ public class VMStringFinal { public static void main(String[] args) { String str = "xcrj"; System.out.println("1》" + str); System.out.println("1》" + str.hashCode()); VMStringFinal vmsp = new VMStringFinal(); vmsp.refTrans(str); // 经过引用的值传递,str的值不会发生变化,仍然是xcrj System.out.println("2》" + str); System.out.println("2》" + str.hashCode()); } public void refTrans(String str) { System.out.println("3》" + str); System.out.println("3》" + str.hashCode()); str = "xcrj2"; System.out.println("4》" + str); System.out.println("4》" + str.hashCode()); } }
结果
1》xcrj 1》3673699 3》xcrj 3》3673699 4》xcrj2 4》113884719 2》xcrj 2》3673699
总述
intern()
方法性能下降Hashtable-开散列(链地址法)
代码
package xcrj; /* * 先 -XX:StringTableSize=1009 * 注意 最小1009 * */ public class VMStringPoolSize { public static void main(String[] args) { try { Thread.sleep(1000000); } catch (InterruptedException e) { e.printStackTrace(); } } }
命令
# 编译 javac -d D:\workspace\idea\JVMDemo\blog\target\classes\ -encoding UTF-8 VMStringPoolSize.java # 运行 java -XX:StringTableSize=1009 -classpath D:\workspace\idea\JVMDemo\blog\target\classes\ xcrj.VMStringPoolSize
结果
字符串常量池位于方法区/永久代中
字符串常量池位于堆区中
更换位置原因:GC对于方法区/永久代的回收频率很低,但字符串常量的使用频率又很高
代码
String str="xcrj";
介绍
代码
String str=new String("xcrj");
介绍
代码
package xcrj; /* * 字符串常量反编译查看 * */ public class VMStringConstPool { public static void main(String[] args) { String str = "xcrj"; String str1 = "xcrj1"; String str2 = "xcrj2"; } }
命令
# 编译 javac -d D:\workspace\idea\JVMDemo\blog\target\classes\ VMStringConstPool.java # 反编译 javap -classpath D:\workspace\idea\JVMDemo\blog\target\classes\ -v xcrj.VMStringConstPool
结果
总述
toString()
方法内部实现有所不同toString()
方法内部return this;
toString()
方法内部new String(value, 0, count);
toString()
方法内部return getClass().getName() + "@" + Integer.toHexString(hashCode()); 就是String str="getClass().getName() + "@" + Integer.toHexString(hashCode())";
代码
package xcrj; public class VMStringToString { public static void main(String[] args) { Object obj = new Object(); VMStringToString vmsts = new VMStringToString(); vmsts.toStr(obj); } public void toStr(Object obj) { String str = obj.toString(); String str1 = obj.toString(); // false System.out.println(str == str1); String strIntern = str.intern(); String str1Intern = str1.intern(); // true System.out.println(strIntern == str1Intern); } }
指令
# 编译 javac -d D:\workspace\idea\JVMDemo\blog\target\classes\ -encoding UTF-8 VMStringToString.java # 反编译 javap -classpath D:\workspace\idea\JVMDemo\blog\target\classes\ -v xcrj.VMStringToString
反编译
总述
注意-字符串拼接至少一个字符串变量
toString()
方法内部new String(value, 0, count);
(由StringBuilder对象拼接完成最后调用)代码
package xcrj; /* * 字符串拼接 * */ public class VMStringBuilder { public static void main(String[] args) { // 字符串常量拼接 String str = "xc" + "rj"; // 字符串常量拼接 final String str1 = "xc"; final String str2 = "rj"; String str3 = str1 + str2; // true System.out.println(str == str3); // 字符串变量拼接 String str4 = "xc"; String str5 = str + "rj"; // false System.out.println(str == str5); } }
指令
# 编译 javac -d D:\workspace\idea\JVMDemo\blog\target\classes\ -encoding UTF-8 VMStringBuilder.java # 反编译 javap -classpath D:\workspace\idea\JVMDemo\blog\target\classes\ -v xcrj.VMStringBuilder
反编译
分析
0: ldc #2 // String xcrj 3: ldc #2 // String xcrj
astore
总述
if (字符串常量池中有这个字符串常量) { 返回这个字符串常量的引用 } else { 在字符串常量池中添加这个字符串常量 返回这个字符串常量的引用 }
代码
package xcrj; public class VMStringIntern { public static void main(String[] args) { String str = "xcrj"; String strIntern = str.intern(); // true System.out.println(str == strIntern); String str1 = new String("xcrj1"); String str1Const = "xcrj1"; String str1Intern = str1.intern(); // false System.out.println(str1 == str1Intern); // true System.out.println(str1Const == str1Intern); Object obj = new Object(); String str2 = obj.toString(); String str2Intern = str2.intern(); // true System.out.println(str2 == str2Intern); StringBuilder sb = new StringBuilder(); sb.append("xcrj2"); String str3 = sb.toString(); String str3Intern = str3.intern(); // fasle System.out.println(str3 == str3Intern); } }
总述
StringBuilder builder=new StringBuilder(capacity)
,给出合适的初始容量(内部char[]大小,无参构造是16)toString()
方法内部new String(value, 0, count);
源码
abstract class AbstractStringBuilder implements Appendable, CharSequence { /** * The value is used for character storage. */ char[] value; /** * The count is the number of characters used. */ int count; /** * For positive values of {@code minimumCapacity}, this method * behaves like {@code ensureCapacity}, however it is never * synchronized. * If {@code minimumCapacity} is non positive due to numeric * overflow, this method throws {@code OutOfMemoryError}. */ private void ensureCapacityInternal(int minimumCapacity) { // overflow-conscious code if (minimumCapacity - value.length > 0) { value = Arrays.copyOf(value, newCapacity(minimumCapacity)); } } /** * Returns a capacity at least as large as the given minimum capacity. * Returns the current capacity increased by the same amount + 2 if * that suffices. * Will not return a capacity greater than {@code MAX_ARRAY_SIZE} * unless the given minimum capacity is greater than that. * * @param minCapacity the desired minimum capacity * @throws OutOfMemoryError if minCapacity is less than zero or * greater than Integer.MAX_VALUE */ private int newCapacity(int minCapacity) { // overflow-conscious code int newCapacity = (value.length << 1) + 2; if (newCapacity - minCapacity < 0) { newCapacity = minCapacity; } return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity; } @Override public String toString() { // Create a copy, don't share the array return new String(value, 0, count); }
总述
总述
package xcrj; public class VMStringInternjdk { public static void main(String[] args) { String str = new String("xcrj"); String strIntern = str.intern(); String str1 = "xcrj"; /* * jdk6:字符串常量池池位于方法区/永久代中 * jdk7=+:字符串常量池位于堆区中 * jdk6/7/8 都是false * */ System.out.println(str == str1); /* * jdk6:字符串常量池池位于方法区/永久代中 * jdk7=+:字符串常量池位于堆区中 * jdk6/7/8 都是true * */ System.out.println(strIntern == str1); String strss = new String("xcrjxcrj"); String strss1 = new String("xcrjxcrj"); // false System.out.println(strss == strss1); String strssIntern = strss.intern(); String strss1Intern = strss1.intern(); // false System.out.println(strss == strss1); // true System.out.println(strssIntern == strss1Intern); String str2 = new String("xcrj2") + new String("xcrj2"); str2.intern(); String str3 = "xcrj2xcrj2"; /* * jdk6:字符串常量池池位于方法区/永久代中 * jdk7=+:字符串常量池位于堆区中 * jdk6:是false * jdk7/8 都是true * */ System.out.println(str2 == str3); String str4 = new String("xcrj4") + "xcrj4"; str4.intern(); String str5 = "xcrj4xcrj4"; /* * jdk6:字符串常量池池位于方法区/永久代中 * jdk7=+:字符串常量池位于堆区中 * jdk6:是false * jdk7/8 都是true * */ System.out.println(str4 == str5); } }
分类 | 参数 | 作用 | 建议 |
---|---|---|---|
String | -XX:StringTableSize | jdk6 字符串常量池默认固定大小是1009;jdk7=+ 字符串常量池默认固定大小是60013 | 否 |
package xcrj; /* * 面试题 * */ public class VMStringFace { public static void main(String[] args) { VMStringFace vmsf = new VMStringFace(); vmsf.face1(); vmsf.face2(); } /* * new String("xcrj") 创建了几个对象? * 总共2个对象: * 字符串常量池中有1个匿名对象 * 堆区中有1个对象 * */ public void face1() { String str = new String("xcrj"); } /* * new String("xc")+new String("rj")创建了几个对象? * 总共6个对象: * 字符串常量池中有2个匿名对象 * 堆区中有2个对象 * StringBuilder对象 * StringBuilder拼接对象完成之后toString()会在堆区创建1个对象 * */ public void face2() { String str = new String("xc") + new String("rj"); } }
反编译