我们知道字符有两种初始化方式:
String s1 = “abc”;
String s2 = new String("def");
这两种有什么区别呢?这时就需要我们看看String的在内存中是怎么存储的了。我们先看下面的图了解其在内存在是怎么存储的:
首先是 String s1 = “abc”;它首先会去常量池去检查是否存在“abc“,如果存在就返回,否则就创建。“abc”的地址给了s1,s1指向了它。而String s2 = new String("def");它会先去堆内存中去创建一个new String()对象,然后去常量池检查是否存在"def" 如果存在就返回,否则创建。“def”的地址给了new String(),而new String()自给有一个地址给了s2。这就是字符串的基本存储过程。
接下来我们看看字符串的一个重要特性:字符串是常量,它们的值在创建之后不能更改。
如下面一段代码
public class TestString { public static void main(String[] args) { String s = "abc"; s+="def"; System.out.println(s); } }
根据上面的分析我们可以知道 s 最开始是指向"abc",后面 s+="def"做个一个字符串拼接,而在内存中并没有直接把"def”拼接在“abc”上,而是先开辟了空间存储“def”,最后把abcdef拼接在一起,开辟了第三块空间。通过这个例子我们可以知道不能变的是字符串的值,即“abc”不能改变,而引用是可以改变的。所以最后 s打印出来的值变了,并不是“abc”发生了变化,而是s指向了新的对象“abcdef”。
接下来我们可以通过1个例子看看
public class TestString { public static void main(String[] args) { String s1 = "abc"; String s2 = "abc" String s3 = new String("abc"); System.out.println(s1==s2) System.out.println(s1==s3); System.out.println(s1.equals(s3)); } }
首先我们要知道==和equals的区别,==比较的是地址,而equals默认比较也是地址,而String重写了equals()方法,比较的是值是否相同。根据上面的理解我们画出内存图
根据上图我们知道了 String s1 = "abc";首先会在常量池中创建“abc”,s1指向此对象,而 String s2 = "abc"首先会在常量池中检查发现存在“abc”,所以s2并不会再创建而是直接指向“abc”,而 String s3 = new String("abc");首先会在堆内存new 一个String对象,然后指向常量池中已经存在的“abc” (不会再创建“abc”),但是new String()给s3是自己的地址,并不是“abc”的地址。所以输出结果为true false true
现在抛出一个问题 String s = “abc”和 String s = new String("abc")有什么区别?
答案详情请见下一篇随笔