Java String s = new String("hello")和String s = "hello"的区别

原创文章,转载请注明出处https://blog.csdn.net/kk123k/article/details/80752476

对于初学者很多人会疑惑Java中的String s = new String("hello")和String s = "hello"究竟有什么区别呢?

下面就来探讨一下,先看以下代码

                String newS1 = new String("hello");
		String newS2 = new String("hello");
		String ss1 = "hello";
		String ss2 = "hello";
		
		System.out.println("ss1="+ss1);
		System.out.println("ss2="+ss2);
		System.out.println("newS1="+newS1);
		System.out.println("newS2="+newS2);
		System.out.println("ss1==ss2是"+(ss1==ss2));
		System.out.println("ss1==newS1是"+(ss1==newS1));
		System.out.println("newS1==newS2是"+(newS1==newS2));


由上结果可知,ss1和ss2其实是同一个对象;而newS1和newS2不是同一个对象;其实JVM内部是这样的



String newS1 = new String("hello")首先会在堆中创建一块内存, 内存地址返回给栈中newS1,然后因为"hello"是常量,JVM会去方法区中的字符串常量池查看是否有"hello"字符串的对象,没有的话就分配一个空间来存放"hello",并将其空间地址存入堆中new出来的对象中;

在新建newS2对象时先去方法区的字符串常量池中寻找"hello"字符串对象,发现已经有了,就直接将其内存地址存入堆中new出来的对象中,同理堆中new出来的对象的内存地址返回给newS2

对于String ss1="hello"这样创建的对象,JVM会直接检查字符串常量池是否已有"hello"字符串对象,如没有,就分配一个内存存放"hello",如有了,则直接将字符串常量池中的地址返回给栈中的ss1而不经过堆中new的对象

所以ss1和ss2指向的是同一个对象

这个时候有人就会有疑问了,既然ss1和ss2指向的是同一个对象,那我修过ss1的值岂不是也同时改变了ss2的值?

显然,改变ss1的值并不会影响ss2以及其它对象的值,原因其实Java的String是一个不可变的类,假设我们对ss1重新赋值时其实是在字符串常量池中重新分配了一块内存然后令ss1指向新对象

我们可以尝试用反射来强行修改字符串常量池中对象的值,来看看会怎样

String内部是由一个char[] value和int hash值构成,但是Java,下面用反射来改变其内部的value值

            //获取String类中的value字段  
	    Field valueFieldOfString = String.class.getDeclaredField("value");
		 
	    //改变value属性的访问权限  
	    valueFieldOfString.setAccessible(true);  
	      
	    //获取ss1对象上的value属性的值  
	    char[] value = (char[]) valueFieldOfString.get(ss1);

	    //把value所引用的数组中的第5个字符为'e'
	    value[4] = 'e';
	    
	        System.out.println("ss1="+ss1);
		System.out.println("ss2="+ss2);
		System.out.println("newS1="+newS1);
		System.out.println("newS2="+newS2);
		System.out.println("ss1==ss2是"+(ss1==ss2));
		System.out.println("ss1==newS1是"+(ss1==newS1));
		System.out.println("newS1==newS2是"+(newS1==newS2));

结果所有最终指向字符串常量池为"hello"的对象最终都会变成"helle"。

其内存原理如下:


用反射强行把方法区中的"hello"中的'o'改成了'e',所以最终指向同一个字符串常量池中的对象的值都会跟着改变

  • 24
    点赞
  • 62
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值