深入浅出了解String对象的创建

本文详细探讨了Java中创建String对象的多种方式,包括直接赋值与使用new关键字的区别,以及字符串常量池的工作原理。通过实例分析,揭示了字符串创建过程中对象的数量变化,帮助读者理解内存管理和性能优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本篇将叙述一下内容

创建字符串的方式有哪些,String 字符串是如何创建的,什么是字符串常量池。

首先讲创建String字符串的方式

显而易见,创建String字符串就几种方式:

在这里插入图片描述
当然对于上面第二种方式也有其他的一些实现方式,但是不常用:
在这里插入图片描述

字符串是如何创建的

知道创建字符串的几种方式后,我们来看看字符串是如何创建的。
我们知道有八种基本数据类型byte,char,short,int,long,float,double,boolean。而String却不属于基本数据类型,String是一种引用数据类型。java虚拟机缓存了Integer、Byte、Short、Character、Boolean包装类在-128~127之间的值的int常量池,简单的效果如下:

在这里插入图片描述
这里可以看出 i3 == i4 结果为false不太正常,或者说是常量池在“作怪”。当创建的是-128~127数值范围内的Integer对象时,java虚拟机并不会给你在堆中创建一个空间存放这个数值,而是引用方法区中的int常量池已存在的数值,把这个常量池中的数值实例的引用直接给Integer对象。而若常量池中没有此数值则自己在堆中创建一个。上图执行的代码实际上是:
在这里插入图片描述

什么是字符串常量池

我们再来看看String s1 = “hello”;其实跟上面的差不多。java虚拟机也维护了一个String常量池,而跟int常量池不同的是String常量池并没有固定的范围,存入String常量池的字符串是在编译期确定的,如本篇开文中的最常见的字符串创建的两种方式,在写完代码生成class文件后,字符串"hello"便会存入该class文件中的String常量池,并且该常量池有且只有这个字符串。
那么s1 与 s2 比较的结果是什么呢
在这里插入图片描述
显而易见结果是false,但是我们必须了解为什么是false。这两种方式的差别最大就是第二个方式使用了new关键字,而new代表新创建一个对象的意思,那么第一个方式就不是创建对象了么,也不是,它是引用了String常量池中的"hello"字符串,不用重新创建对象。但是实际上这两个字符串使用的还是同一个"hello",new String(“hello”)中的字符串其实也是从String常量池中拿来用的,只是在堆中心新创建了一个引用此字符串的对象,可通过下图理解:
在这里插入图片描述
这里有个问题,上图创建了几个对象?答案很简单,2个。哪两个个?是图中的s1和s2?其实这样说也没问题,但是这两个对象具体是堆中新创建的对象和String常量池中的hello对象。为什么不说是s1呢,其实s1也就是直接引用String常量池中的对象,先有后者再有前者。

接着我们可以来看看一些经典题目了

  以下创建了多少对象?
  		String s1 = "he";
		String s2 = "llo";
		String s3 = new String("hello");

答案是4个,分别为String常量池中的"he"、“llo”、“hello”、和堆中新创建的一个对象。注意这里的new String(“hello”)中的hello在编译期也会存入String常量池。

   以下创建了多少对象?
   		String s1 = "he"+"llo";
		String s2 = new String("hello");

答案是2个,这里的"he"+“llo"java做了优化机制,直接把结果hello存入String常量池而不是分别把"he"和"llo"存入(这里存入"he"和"llo"也无意义,因为并无使用到)。注意: 若是new String(“hello”+“world”);此语句也只会在常量池中存入"helloworld”,并不会分别存入。

   以下创建了多少对象?
  	    String s1 = "he";
		String s2 = "llo";
		String s3 = s1 + "llo";

答案是3个,分别是常量池中的"he"、“llo”、和堆中的一个内容为"hello"的对象。这里的s1+"llo"实际上是使用StringBuffer对象连接的(查看jdk的API文档可知),笔者在这里也画了个图解。
在这里插入图片描述
可能会有人产生疑问了,为什么String常量池里没有存入"hello"呢?笔者刚才也提过,常量池中的内容是在编译期确定的,s1+"llo"中,java虚拟机并不知道其结果是什么,而且此操作涉及StringBuffer对象也就是涉及其他类,在编译期并无法使用,只有等到运行时才能进行。所以结果"hello"是运行时产生的,不存在于常量池中。

当然也有其他一些需要注意细节的题目:

    以下代码创建了多少对象
    	String s1 = "he";
		String s2 = "llo";
		String s3 = s1 + "abc";

答案是4个,和上一题类似,只不过上题中的"llo"在前面s2中已存入常量池。

当然笔者也在网上找了一些资料:
在这里插入图片描述
按照笔者的分析答案都是2个,而不是题中给出的答案。首先引用str1和str2是存在栈中的,并不是对象,常量池中分别存的只有"AB"和"ABC"(上面说到的优化机制),加上堆中分别有一个对象,总和就2个对象。

以上就是笔者的分析,若有错误,欢迎读者指出,有时间会更新。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值