您的位置:首页 > 编程语言 > Java开发

java中String和new String还有对象中的String字符串在内存中的存储

2018-01-25 18:04 387 查看
 参考自: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 中。如果有什么意见或建议请在下方留言,再次感谢原博主
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  String 底层分析