写了那么久的String字符串,你可能根本不懂它!

简介: String str和new String()有什么区别?这个问题之前在面试中有被问到过一次,当时面试结束后也写了自己关于这个题目的理解,不过最近在看Effect Java的时候发现书中也提到了关于String的用法,刚好就放到一起聊一下。

网络异常,图片无法展示
|


本文收录于JavaStarter ,里面有我完整的Java系列文章,学习或面试都可以看看


(一)引言


String str和new String()有什么区别?这个问题之前在面试中有被问到过一次,当时面试结束后也写了自己关于这个题目的理解,不过最近在看Effect Java的时候发现书中也提到了关于String的用法,刚好就放到一起聊一下。


(二)关于String字符串


String应该是Java中最常用的一个对象,他不是八种基本数据类型的其中之一,但是我随便翻了一下项目代码,用String定义的变量超过百分之八十。


publicfinalclassStringimplementsjava.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */privatefinalcharvalue[];
/** Cache the hash code for the string */privateinthash; // Default to 0}

关于String的几个基本知识点在String类的源码定义中就能看到:


1、在JDK8中,String实例的值是通过char数据存储的。(JDK9时,String实例的存储由char变成了byte数组,原因是使用byte数组可以减少一半的内存)


2、String类被final修饰,因此String不能被继承,value变量被final修饰,因此String实例不能被修改


3、String类实现了Serializable, Comparable, CharSequence接口


(三)关于字符串常量池


字符串常量池是虚拟机中的内容,但是接下来的几个问题需要用到,就简单了解下。为了让String字符串可以复用,Java虚拟机中设置了一种叫做字符串常量池的东西。


Java为了避免产生大量的String对象,设计了一个字符串常量池。工作原理是这样的,创建一个字符串时,JVM首先为检查字符串常量池中是否有值相等的字符串,如果有,则不再创建,直接返回该字符串的引用地址,若没有,则创建,然后放到字符串常量池中,并返回新创建的字符串的引用地址。因此看下面这段代码:


Strings1="abc";
Strings2="abc";
System.out.println(s1==s2);  //返回true

返回的结果就是true,因为指向了同一个对象。


关于字符串常量池的位置,在不同版本的JDK中有所不同:


JDK1.7之前字符串常量池属于运行时常量池的一部分,存放在方法区


JDK1.7之后字符串常量池被从方法区拿到了堆中


(四)String str和new String()有什么区别


回到开始的问题,String str和new String()有什么区别?区别在于,String str创建的字符串保存在字符串常量池中,并且可复用。new String()创建的字符串按照最标准的对象创建方式,生成在堆中,并且一个new String会在堆中创建一个对象。下面这张图应该可以把这个流程讲清楚。


网络异常,图片无法展示
|


s1==s2返回true,s1==s3返回false。


(五)new String()方法创建了几个对象


又是个好问题,这道题的答案是一个或者两个。


写一段代码:


publicclasstest {
publicstaticvoidmain(String[] args) {
Strings1=newString("ab");
    }
}

编译后通过javap -v test.class查看字节码:


网络异常,图片无法展示
|


1、在常量池中创建了ab对象,位置在#3


网络异常,图片无法展示
|


2、在堆中创建了ab对象


这样的情况下创建了两个对象,一个在常量池中,一个在堆中。


再写一段代码:

publicclasstest {
publicstaticvoidmain(String[] args) {
Strings1="ab";
Strings2=newString("ab");
    }
}

同样的方式查看字节码:


网络异常,图片无法展示
|


首先s1="ab"在常量池中创建了ab对象,存放在常量池的#2位置里,这个时候new


String就只在堆中创建了一个String对象,常量池中因为已经有了,就不会再创建了。


这样的情况下,只创建了一个对象。


(六)总结


虽说怎么写代码都能实现一定的功能,但是有时候换种写法可以省下很多资源。比如将:


Stringstr=newString("abc")

写成:

Stringstr="abc"

虽然只是小小的改动,但是在频繁调用的方法中,就有可能避免创建了百万个String实例。


对于有一定开发经验的程序员,建议可以读一下《Effect-Java》,里面有许多写代码的更优方式。


我是鱼仔,我们下期再见!

相关文章
|
1月前
|
存储 缓存 测试技术
CMake String函数:如何巧妙地在cmake中操作字符串
CMake String函数:如何巧妙地在cmake中操作字符串
80 0
|
3月前
|
存储 编译器 Linux
【字符串探秘:手工雕刻的String类模拟实现大揭秘】(下)
【字符串探秘:手工雕刻的String类模拟实现大揭秘】
|
3月前
|
编译器 C语言 C++
【字符串探秘:手工雕刻的String类模拟实现大揭秘】(中)
【字符串探秘:手工雕刻的String类模拟实现大揭秘】
|
3月前
|
存储 编译器
【字符串探秘:手工雕刻的String类模拟实现大揭秘】(上)
【字符串探秘:手工雕刻的String类模拟实现大揭秘】
|
3月前
String字符串类型时间比较(根据时间判断返回 ‘已结束’或‘进行中‘’)
String字符串类型时间比较(根据时间判断返回 ‘已结束’或‘进行中‘’)
23 1
|
2月前
|
存储 XML 缓存
Java字符串内幕:String、StringBuffer和StringBuilder的奥秘
Java字符串内幕:String、StringBuffer和StringBuilder的奥秘
26 0
|
3月前
|
C++
c++:string相关的oj题(把字符串转换成整数、344.反转字符串、387. 字符串中的第一个唯一字符、917. 仅仅反转字母)
c++:string相关的oj题(把字符串转换成整数、344.反转字符串、387. 字符串中的第一个唯一字符、917. 仅仅反转字母)
54 0
|
3月前
|
C++ 索引
c++:string相关的oj题(415. 字符串相加、125. 验证回文串、541. 反转字符串 II、557. 反转字符串中的单词 III)
c++:string相关的oj题(415. 字符串相加、125. 验证回文串、541. 反转字符串 II、557. 反转字符串中的单词 III)
42 0
|
存储 编译器 Linux
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”
标准库中的string类(中)+仅仅反转字母+字符串中的第一个唯一字符+字符串相加——“C++”“Leetcode每日一题”
|
13天前
|
JavaScript
js 字符串String转对象Object
该代码示例展示了如何将一个以逗号分隔的字符串(`&#39;1.2,2,3,4,5&#39;`)转换为对象数组。通过使用`split(&#39;,&#39;)`分割字符串并`map(parseFloat)`处理每个元素,将字符串转换成浮点数数组,最终得到一个对象数组,其类型为`object`。