参考自:http://blog.csdn.net/zhangjg_blog/article/details/18319521 的博客,很多知识和代码都来源此,感兴趣的同学可以去看看
一直以来,所有人都说,java中的String类型是不可变的,可是为什么不可变确很少有人说的透彻,String和new String的区别,对象中的String和直接定义一个String是否有区别,一直都是一知半解。看了很多文档都是各种猜测,没有具体代码来证明。今天看了上面的博客做了一些测试,有一些心得。String类型一直是一个特殊的数据类型,在创建的时候就是不可变的,会在Stringconstant pool中创建一个常量,当我们再次创建一个字符串的时候,jvm会先去String constant pool 中检索这个这个常量是否存在,如果存在则将引用返回,如果不存在,则创建新的常量,然后将引用返回。那么使用new String的方法创建?或者是在一个对象的实例中创建一个字符串?内存中这个值会如何存储?是在Heap中直接开辟空间存储,还是会在Stringconstant pool 中创建,然后在Heap中创建一个引用?接下来,通过代码来证明,在内存中String究竟是如何存储的
首先是String和new String的区别
public static void main(String[] args) throws Exception {
String hello="hello world";
String xx=new String("hello world");
String yy="hello world";
//输出判断内存地址是否相等
System.out.println("xx==hello : "+ (xx==hello));
System.out.println("yy==hello : "+ (yy==hello)+"\n");
//通过反射修改hello的value值
Field hello_field=String.class.getDeclaredField("value");
hello_field.setAccessible(true);
char[] value=(char[])hello_field.get(hello);
value[5]='_';
//首先输出修改结果
System.out.println("Hello: "+hello+"\n");
//然后判断内存地址是否有变化
System.out.println("xx==hello : "+ (xx==hello));
System.out.println("yy==hello:"+(hello==yy));
System.out.println("xx==yy:"+(xx==yy)+"\n");
//最后输出所有值的结果
System.out.println("xx: "+xx);
System.out.println("yy: "+yy);
System.out.println("Hello: "+hello);
}
代码执行结果
xx==hello : false
yy==hello : true
Hello: hello_world
xx==hello : false
yy==hello:true
xx==yy:false
xx: hello_world
yy: hello_world
Hello: hello_world
根据结果可以判断,无论是String还是new String最终都指向了String constant pool中,只不过是String直接指向了Stringconstant pool中。而new String是在Heap中创建了一个指向String constant pool中的引用。那么,对象中String是否也是这样的?那么我们是否可以这样推测,在java中所有的String类型的字符串,最终都会指向Stringconstant pool 中?
然后是String和Object的区别
import java.lang.reflect.Field;
public class StringTest {
public String name="hello world";
public String phone;
public StringTest(String phone) {
// TODO Auto-generated constructor stub
this.phone=phone;
}
public static void main(String[] args) throws Exception {
StringTest a = new StringTest("hello world");
StringTest b = new StringTest("hello world");
String c = "hello world";
String e = new String("hello world");
//首先判断不同对象中的字符串地址是否相等
System.out.println("a.name==a.phone:"+(a.name==a.phone));
System.out.println("a.name==b.phone:"+(a.name==b.phone));
System.out.println("a.name==c:"+(a.name==c));
System.out.println("e==c:"+(e==c)+"\n");
//然后修改c在内存中的值
Field hello_field=String.class.getDeclaredField("value");
hello_field.setAccessible(true);
char[] value=(char[])hello_field.get(c);
value[5]='_';
//首先判断不同对象中的字符串地址是否相等
System.out.println("a.name==a.phone:"+(a.name==a.phone));
System.out.println("a.name==b.phone:"+(a.name==b.phone));
System.out.println("a.name==c:"+(a.name==c));
System.out.println("e==c:"+(e==c)+"\n");
//直接输出值判断是否发生变化
System.out.println("a.name: "+a.name);
System.out.println("b.name: "+b.name);
System.out.println("a.phone: "+a.phone);
System.out.println("b.phone: "+b.phone);
System.out.println("c: "+c);
System.out.println("e: "+e);
}
}
代码执行结果
a.name==a.phone:true
a.name==b.phone:true
a.name==c:true
e==c:false
a.name==a.phone:true
a.name==b.phone:true
a.name==c:true
e==c:false
a.name: hello_world
b.name: hello_world
a.phone: hello_world
b.phone: hello_world
c: hello_world
e: hello_world
根据执行结果可以看出,不同对象中的String值相等时,其指向的是同一个String constant pool中的地址,如果我们修改了其中一个值得时候,所有的引用都会发生改变,而且其内存地址的比较并没有发生变化。所以我们的推测应该是正确的,因时间关系,没有了测试数组和其他的关于String类型的字符串是否也是如此,不过根据上面的结果,我们应该可以大胆猜测,java中,如果定义了String类型的字符串,最终的都存在String constant pool 中。如果有什么意见或建议请在下方留言,再次感谢原博主