Windows电脑,idea中。双击shift,输入String,便可出来。java
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; .... }
从这部分源码中,咱们就能够很好的理解“1.1 String 的特性”中的内容了!!!字符串,字符串,就是字符构建起来的串。面试
public class StringTest { @Test public void test1() { // String name = "abc"; 字面量的定义方式 String name = "abc"; String des = "abc"; name = "hell world"; System.out.println("name:"+name);// hello world System.out.println("des:"+des);// abc } @Test public void test2() { final int a = 2; a = 3; // 编译不经过 } }
第一个问题:为何name = "hell world",编译成功,并能运行,不是说“它们的值在建立以后不能更改”吗?;而test2()中却编译失败?数组
首先,String属性引用类型,而int是基本类型。ide
引用类型变量存储地址值,而a是一个指向int类型的引用,指向2这个字面值。所以final int 修饰的变量就变为常量了,常量是不能修改其值的,因此test2()编译失败。oop
那么怎么理解String 底层存储使用final修饰的char型数组,更改其值为何编译成功,并能运行?简单的JVM走一波。图一:this
从图中咱们能够看出:idea
图二:code
从图中咱们能够看出:对象
@Test public void test3() { String s1="javaWeb"; String s2="javaWeb"; String s3 = new String("javaWeb"); String s4 = new String("javaWeb"); System.out.println(s1==s2); System.out.println(s1==s3); System.out.println(s1==s4); System.out.println(s3==s4); }
直观判断:blog
集合JVM判断:
结合JVM图形就能够很清楚的明白到底为何错,为何对了。
public class Person { String name; int age; public Person(String name, int age) { this.name = name; this.age = age; } }
@Test public void test4() { Person p1 = new Person("Tom", 12); Person p2 = new Person("Tom", 12); System.out.println(p1.name==p2.name);// true?false? }
显然为true,Tom存储在字符串常量池中,有且仅有一份。故p1.name==p2.name必然为true
再来:
@Test public void test4() { Person p1 = new Person("Tom", 12); Person p2 = new Person("Tom", 12); System.out.println(p1.name==p2.name); p2.name="cxk"; System.out.println(p1.name==p2.name);// true?false }
确定是false, p2.name="cxk";会先在字符串常量池中查找,没有就在常量池中建一个, p2.name地址指向它便可。【字符串的不可变性】
String s = new String("abc");方式建立对象,在内存中建立了几个对象?
答:2个。一个是堆空间中new结构,另外一个是char[ ]对应的常量池中的数据:”abc“;
来,搞一下这个。
public void test3(){ String s1 = "javaEE"; String s2 = "hadoop"; String s3 = "javaEEhadoop"; String s4 = "javaEE" + "hadoop"; String s5 = s1 + "hadoop"; String s6 = "javaEE" + s2; String s7 = s1 + s2; System.out.println(s3 == s4); System.out.println(s3 == s5); System.out.println(s3 == s6); System.out.println(s3 == s7); System.out.println(s5 == s6); System.out.println(s5 == s7); System.out.println(s6 == s7); String s8 = s6.intern(); System.out.println(s3 == s8); }
结论:
代码一:
public class StringTest2 { String str = new String("good"); char[] ch = {'t', 'e', 's', 't'}; public void change(String str, char ch[]) { str = "test ok"; System.out.println("======"+str); ch[0] = 'b'; } public static void main(String[] args) { StringTest2 ex = new StringTest2(); ex.change(ex.str, ex.ch); System.out.print(ex.str + " and "); System.out.println(ex.ch); } }
输出结果是多少?
解析:作这道题必须明白几个知识点
分析:
代码二:
public class StringTest2 { String str = new String("good"); char[] ch = {'t', 'e', 's', 't'}; public void change(String str, char ch[]) { // 第二步: //对于方法中的str,因为第一步的赋值操做,它的地址值和“String str = new String("good");”中的str同样,内容都为good。 //接下来方法中对它进行赋值操做“test ok”。 //因为String类型的不可变性(看源码类为final修饰,数据存储结构为也为final修饰的char型数组),不可修改。 //所以JVM执行'str ="test ok";'时会在字符串常量池中新建一个“test ok”而且更新方法中str的地址值。 //至此两个str的地址值不一样了,指向的内容也不一样了。 能够看“代码三”中的对比结果。 str = "test ok"; // 第二步; //对于方法中的ch,因为第一步的赋值操做,它的地址值和“char[] ch = {'t', 'e', 's', 't'};”中的ch同样,内容都为test。 //接下来,在方法中执行"ch[0] = 'b';" 数组中的第一个元素被赋值为b。因为是引用类型,此时类中成员变量char[] ch = {'t', 'e', 's', 't'};值也变为best。 ch[0] = 'b'; } public static void main(String[] args) { StringTest2 ex = new StringTest2(); // 第一步 // 传递的两个实参,参数一,其实是把StringTest2类中成员变量str的地址值复制一份给StringTest2类中change方法中的形参变量str // 同理,StringTest2类中成员变量ch(数组:也是引用类型)的地址值复制一份给StringTest2类中change方法中的形参变量ch[] ex.change(ex.str, ex.ch); System.out.print(ex.str + " and "); System.out.println(ex.ch); } }
代码三:
public class StringTest2 { String str = new String("good"); char[] ch = {'t', 'e', 's', 't'}; public void change(String str, char ch[]) { System.out.print("赋值以前两个str的地址值比较为:"); System.out.println(this.str==str); str = "test ok"; System.out.print("赋值以后两个str的地址值比较为:"); System.out.println(this.str==str); System.out.println("====================分割线========================"); ch[0] = 'b'; } public static void main(String[] args) { StringTest2 ex = new StringTest2(); ex.change(ex.str, ex.ch); System.out.print(ex.str + " and "); System.out.println(ex.ch); } }
结果: