String 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 public final class String implements java .io.Serializable, Comparable<String>, CharSequence { private final char value[]; private int hash; public int hashCode () { int h = hash; if (h == 0 && value.length > 0 ) { char val[] = value; for (int i = 0 ; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; } public boolean equals (Object anObject) { if (this == anObject) { return true ; } if (anObject instanceof String) { String anotherString = (String)anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0 ; while (n-- != 0 ) { if (v1[i] != v2[i]) return false ; i++; } return true ; } } return false ; } }
String的存储 1 2 NewUnsafeTest.java NewUnsafeTest.class
String s=”abc” 存储在常量区??? String str=new String(“abc”) 存储在堆区
源代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 public static void main (String[] args) throws NoSuchFieldException, IllegalAccessException { Unsafe unsafe = getUnsafe(); final String s = "abc" ; String s1 = "abc" ; System.out.println(s==s1); Field valueInString = String.class.getDeclaredField("value" ); long offset = unsafe.objectFieldOffset(valueInString); long base = unsafe.arrayBaseOffset(char [].class); long scale = unsafe.arrayIndexScale(char [].class); char [] values = (char []) unsafe.getObject(s, offset); unsafe.putChar(values, base + scale * 2 , 'd' ); System.out.println("s:" + s + " s1:" + s1); s1="abc" ; String s2 = "abc" ; String s3 = new String ("abc" ); System.out.println(s==s1); System.out.println(s.equals(s1)); System.out.println("s:" + s + " s1:" + s1 + " s2:" + s2 + " s3:" + s3); Field valueField=String.class.getDeclaredField("value" ); valueField.setAccessible(true ); System.out.println("c" ); System.out.println("c" ==(s1.substring(2 ))); System.out.println(((char [])valueField.get(s1))[2 ]+"\t" +((char [])valueField.get("c" ))[0 ]); System.out.println(((char [])valueField.get(s1))[2 ]==((char [])valueField.get("abcd" ))[2 ]); System.out.println(((char [])valueField.get(s1))[2 ]+"\t" +((char [])valueField.get("abc" ))[2 ]); System.out.println(((char [])valueField.get(s1))[2 ]==((char [])valueField.get("abc" ))[2 ]); System.out.println("d" .equals(s1.substring(2 ))); System.out.println("abc" ); char [] ori=new char []{'a' ,'b' ,'c' }; String s4=new String (ori); System.out.println(s4); values= (char []) unsafe.getObject(s4,offset); unsafe.putChar(values,base+scale*2 ,'d' ); System.out.println(s4); System.out.println(Arrays.toString(ori)); unsafe.putChar(ori,base+scale*2 ,'d' ); System.out.println(Arrays.toString(ori)); String s5 = "" ; values = (char []) unsafe.getObject(s5, offset); System.out.println("values: " +Arrays.toString(values)); values = ori; System.out.println(values.length); values = ori; System.out.println(values.length); values = ori; values = ori; values = ori; values = ori; values = ori; values = ori; values = ori; values = ori; values = ori; values = ori; values = ori; values = ori; System.out.println(values.length); System.out.println("s5: " + s5); System.out.println("values: " + Arrays.toString(values)); System.out.println("ori: " + Arrays.toString(ori)); unsafe.putChar(values, base + scale * 2 , 'x' ); System.out.println("s5: " + s5); System.out.println("values: " + Arrays.toString(values)); System.out.println("ori: " + Arrays.toString(ori)); unsafe.putChar(ori, base + scale * 2 , 'y' ); System.out.println("s5: " + s5); System.out.println("values: " + Arrays.toString(values)); System.out.println("ori: " + Arrays.toString(ori)); } private static Unsafe getUnsafe () { Unsafe unsafe = null ; try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe" ); theUnsafe.setAccessible(true ); unsafe = (Unsafe) theUnsafe.get(Unsafe.class); } catch (Exception e) { e.printStackTrace(); } finally { return unsafe; } }
Result:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 true s==s1 //编译期替换 "abc" == s1 s:abc s1:abd true s==s1 true s.equals(s1) s:abc s1:abd s2:abd s3:abd c "c" false "c".equals(s1.substring(2))) d c ((char[])valueField.get(s1))[2]+"\t"+((char[])valueField.get("c"))[0] false ((char[])valueField.get(s1))[2] == ((char[])valueField.get("c"))[0] d d ((char[])valueField.get(s1))[2]+"\t"+((char[])valueField.get("abc"))[2] true ((char[])valueField.get(s1))[2] == ((char[])valueField.get("abc"))[2] true "d".equals(s1.substring(2)) abd new String("abc") abc new String( new char[]{'a','b','c'} ) abd s4: unsafe 修改内存 [a, b, c] ori: 内存不变 [a, b, d] ori: unsafe修改内存 Process finished with exit code 0
s=abc而s1=abd 参见字节码文件NewUnsafeTest.class
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 public static void main (String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException { Unsafe unsafe = getUnsafe(); String s = "abc" ; String s1 = "abc" ; System.out.println("abc" == s1); Field valueInString = String.class.getDeclaredField("value" ); long offset = unsafe.objectFieldOffset(valueInString); long base = (long )unsafe.arrayBaseOffset(char [].class); long scale = (long )unsafe.arrayIndexScale(char [].class); char [] values = (char [])((char [])unsafe.getObject("abc" , offset)); unsafe.putChar(values, base + scale * 2L , 'd' ); System.out.println("s:abc s1:" + s1); s1 = "abc" ; String s2 = "abc" ; String s3 = new String ("abc" ); System.out.println("abc" == s1); System.out.println("abc" .equals(s1)); System.out.println("s:abc s1:" + s1 + " s2:" + s2 + " s3:" + s3); Field valueField = String.class.getDeclaredField("value" ); valueField.setAccessible(true ); System.out.println("c" ); System.out.println("c" == s1.substring(2 )); System.out.println(((char [])((char [])valueField.get(s1)))[2 ] + "\t" + ((char [])((char [])valueField.get("c" )))[0 ]); System.out.println(((char [])((char [])valueField.get(s1)))[2 ] == ((char [])((char [])valueField.get("abcd" )))[2 ]); System.out.println(((char [])((char [])valueField.get(s1)))[2 ] + "\t" + ((char [])((char [])valueField.get("abc" )))[2 ]); System.out.println(((char [])((char [])valueField.get(s1)))[2 ] == ((char [])((char [])valueField.get("abc" )))[2 ]); System.out.println("d" .equals(s1.substring(2 ))); System.out.println("abc" ); char [] ori = new char []{'a' , 'b' , 'c' }; String s4 = new String (ori); System.out.println(s4); values = (char [])((char [])unsafe.getObject(s4, offset)); unsafe.putChar(values, base + scale * 2L , 'd' ); System.out.println(s4); System.out.println(Arrays.toString(ori)); unsafe.putChar(ori, base + scale * 2L , 'd' ); System.out.println("ori: " + Arrays.toString(ori)); String s5 = "" ; values = (char [])((char [])unsafe.getObject(s5, offset)); System.out.println("values: " + Arrays.toString(values)); System.out.println(ori.length); System.out.println(ori.length); System.out.println(ori.length); System.out.println("s5: " + s5); System.out.println("values: " + Arrays.toString(ori)); System.out.println("ori: " + Arrays.toString(ori)); unsafe.putChar(ori, base + scale * 2L , 'x' ); System.out.println("s5: " + s5); System.out.println("values: " + Arrays.toString(ori)); System.out.println("ori: " + Arrays.toString(ori)); unsafe.putChar(ori, base + scale * 2L , 'y' ); System.out.println("s5: " + s5); System.out.println("values: " + Arrays.toString(ori)); System.out.println("ori: " + Arrays.toString(ori)); } private static Unsafe getUnsafe () { Unsafe unsafe = null ; try { Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe" ); theUnsafe.setAccessible(true ); unsafe = (Unsafe)theUnsafe.get(Unsafe.class); return unsafe; } catch (Exception var5) { var5.printStackTrace(); return unsafe; } finally { ; } }
“abc”==s1 & “abc”.equals(s1) –> true,true Java.lang.String: Strings are constant; their values cannot be changed after they are created. String buffers support mutable strings. Because String objects are immutable they can be shared.
Because String objects are immutable they can be shared. “abc” is shared……
1 2 String s1="abc" 字符串"abc" 引用指向内存常量---> "abd"
s3=”abd” & s4=”abc” 1 2 3 4 5 6 7 8 9 10 11 12 13 public String (String original) { this .value = original.value; this .hash = original.hash; } public String (char value[]) { this .value = Arrays.copyOf(value, value.length); } public static char [] copyOf(char [] original, int newLength) { char [] copy = new char [newLength]; System.arraycopy(original, 0 , copy, 0 , Math.min(original.length, newLength)); return copy; }
反射修改常量值
不能修改的原因是编译期替换
避免编译期替换
构造方法中对常量赋值1 2 3 4 5 6 class Test { private final String FINAL_STR; public Test () { this .FINAL_STR="FINAL" ; } }
三目运算符1 2 3 4 5 class Test { private final String FINAL_STR = null == null ? "FINAL" :"" ; public Test () { } }