老生常谈Java String字符串(必看篇)

作者:jingxian 时间:2023-06-20 19:56:20 

Java中字符串对象创建有两种形式,一种为字面量形式,如String str = "hello";,另一种就是使用new这种标准的构造对象的方法,如String str = new String("hello");

对于这样的常识,不再赘述。

首先String类是final类,为什么定义成final形式呢?

简单点说,对于如此高频率被使用的数据类型,设计者们认为已经设计的足够优秀了,不需要被继承,否则胡乱继承重写可能会降低程序的性能。

正如标题所述,既然深入,那我们就挖下String在jvm层面的小动作。

先解释字面量创建的形式:

当代码中出现字面量形式创建字符串对象时,JVM首先会对这个字面量进行检查,如果字符串常量池中存在相同内容的字符串对象的引用,则将这个引用返回,否则新的字符串对象被创建,然后将这个引用放入字符串常量池,并返回该引用。

如下所示:


String str1 = "hello" ;

当我们第一次创建的时候,这里我们认为没有内容为hello的对象存在。JVM通过字符串常量池查找不到内容为hello的字符串对象存在,那么会创建这个字符串对象,然后将刚创建的对象的引用放入到字符串常量池中,并且将引用返回给变量str1

如果接下来有这样一段代码


String str2 = "hello" ;

同样JVM还是要检测这个字面量,JVM通过查找字符串常量池,发现内容为”hello”字符串对象存在,于是将已经存在的字符串对象的引用返回给变量str2。注意这里不会重新创建新的字符串对象。

验证是否为str1和str2是否指向同一对象,我们可以通过这段代码


System.out.println(str1 == str2);

结果为true。

第二种使用new创建:


String str3 = new String("hello");

当我们使用了new来构造字符串对象的时候,不管字符串常量池中有没有相同内容的对象的引用,新的字符串对象都会创建。因此我们使用下面代码测试一下,


String str3 = new String("hello");
System.out.println(str1 == str3);

结果为false。说明这两个引用指向不同的对象。

intern

对于上面使用new创建的字符串对象,如果想将这个对象的引用加入到字符串常量池,可以使用intern方法。

调用intern后,首先检查字符串常量池中是否有该对象的引用,如果存在,则将这个引用返回给变量,否则将引用加入并返回给变量。


String str4 = str3.intern();
System.out.println(str4 == str1);

结果为true。

疑难问题

前提条件?

字符串常量池实现的前提条件就是Java中String对象是不可变的,这样可以安全保证多个变量共享同一个对象。如果Java中的String对象可变的话,一个引用操作改变了对象的值,那么其他的变量也会受到影响,显然这样是不合理的。

引用 or 对象

字符串常量池中存放的时引用还是对象,这个问题是最常见的。字符串常量池存放的是对象引用,不是对象。在Java中,对象都创建在堆内存中。字符串常量池存在于堆内存中的永久代

优缺点

字符串常量池的好处就是减少相同内容字符串的创建,节省内存空间。

如果硬要说弊端的话,就是牺牲了CPU计算时间来换空间。CPU计算时间主要用于在字符串常量池中查找是否有内容相同对象的引用。不过其内部实现为HashTable,所以计算成本较低。

GC回收?

因为字符串常量池中持有了共享的字符串对象的引用,这就是说是不是会导致这些对象无法回收?

首先问题中共享的对象一般情况下都比较小。据我查证了解,在早期的版本中确实存在这样的问题,但是随着弱引用的引入,目前这个问题应该没有了。

intern使用?

关于使用intern的前提就是你清楚自己确实需要使用。比如,我们这里有一份上百万的记录,其中记录的某个值多次为美国加利福尼亚州,我们不想创建上百万条这样的字符串对象,我们可以使用intern只在内存中保留一份即可。

总有例外?

你知道下面的代码,会创建几个字符串对象,在字符串常量池中保存几个引用么?


String test = "a" + "b" + "c";

答案是只创建了一个对象,在常量池中也只保存一个引用。我们使用javap反编译看一下即可得知。

实际上在编译期间,已经将这三个字面量合成了一个。这样做实际上是一种优化,避免了创建多余的字符串对象,也没有发生字符串拼接问题。

来源:http://www.cnblogs.com/xinde123/p/7339911.html

标签:Java,String,字符串
0
投稿

猜你喜欢

  • JAVA验证身份证号码有效性的实例代码

    2021-08-20 13:52:06
  • Unity实现图形相交检测

    2021-09-16 09:31:01
  • 基于Java随机生成手机短信验证码的实例代码

    2023-12-22 02:50:49
  • C#日历样式的下拉式计算器实例讲解

    2022-05-07 20:11:33
  • Android封装实现短信验证码的获取倒计时

    2023-06-28 22:57:23
  • Android通过AIDL在两个APP之间Service通信

    2022-04-15 23:58:27
  • C语言由浅入深讲解文件的操作下篇

    2022-12-05 21:21:54
  • SpringMvc接收参数方法总结(必看篇)

    2022-10-02 12:28:54
  • C# Windows API应用之基于FlashWindowEx实现窗口闪烁的方法

    2023-06-30 12:55:22
  • C#中using的三种用法

    2022-08-04 05:10:59
  • C#合并多种格式文件为PDF的方法

    2023-12-11 17:46:58
  • GridView实现桌面图标显示案例

    2021-12-24 03:23:08
  • Android双击退出的实现方法

    2022-08-17 19:23:37
  • 关于maven全局配置文件settings.xml解析

    2023-01-08 09:04:04
  • C#使用随机数编写班级点名器的示例代码

    2022-05-26 11:04:51
  • Opencv图像处理之轮廓外背景颜色改变

    2022-02-17 01:33:34
  • 基于Java ActiveMQ的实例讲解

    2023-08-24 08:39:38
  • Java实现FTP批量大文件上传下载篇2

    2021-07-22 02:30:31
  • Android外部存储无法访问问题解决方法

    2021-12-17 06:52:12
  • mybatis中mapper-locations的作用

    2023-11-10 18:02:58
  • asp之家 软件编程 m.aspxhome.com