深入浅出了解String对象的创建
本篇将叙述一下内容
创建字符串的方式有哪些,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个对象。
以上就是笔者的分析,若有错误,欢迎读者指出,有时间会更新。