服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 详细图解Java中字符串的初始化

详细图解Java中字符串的初始化

2021-12-09 10:47初念初恋 Java教程

字符串广泛应用在Java编程中,在Java中字符串属于对象,Java提供了String类来创建和操作字符串,下面这篇文章主要给大家介绍了Java中字符串初始化的相关资料,需要的朋友可以参考下

前言

在深入学习字符串类之前,我们先搞懂jvm是怎样处理新生字符串的。当你知道字符串的初始化细节后,再去写string s = "hello"string s = new string("hello")等代码时,就能做到心中有数。

首先得搞懂字符串常量池的概念,下面进入正文吧。

常量池

把经常用到的数据存放在某块内存中,避免频繁的数据创建与销毁,实现数据共享,提高系统性能。

八种基础数据类型除了float和double都实现了常量池技术。在近代的jdk版本中(1.7后),字符串常量池被实现在java堆内存中。

下面通过三行代码让大家对字符串常量池建立初步认识:

?
1
2
3
4
5
public static void main(string[] args) {
    string s1 = "hello";
    string s2 = new string("hello");
    system.out.println(s1 == s2);   //false
}

先来看看第一行代码string s1 = "hello";

详细图解Java中字符串的初始化

直接通过双引号( string s1 = "hello")声明字符串的方式,虚拟机首先会到字符串常量池中查找该字符串是否已经存在。如果存在会直接返回该引用,如果不存在则会在堆内存中创建该字符串对象,然后到字符串常量池中注册该字符串。

上面的代码中( string s1 = "hello")虚拟机首先会到字符串常量池中查找是否有存在hello字符串对应的引用。发现没有后会在堆内存创建hello字符串对象(内存地址0x0001),然后到字符串常量池中注册地址为0x0001的hello对象,也就是添加指向0x0001的引用。最后把字符串对象返回给s1。

下面看string s2 = new string("hello");

详细图解Java中字符串的初始化

当我们使用new关键字创建字符串对象的时候,jvm将不会查询字符串常量池,它将会直接在堆内存中创建一个字符串对象,并返回给所属变量。

所以s1和s2指向的是两个完全不同的对象,判断s1 == s2的时候会返回false。

再来看下面的示例:

?
1
2
3
4
5
6
public static void main(string[] args) {
    string s1 = new string("hello ") + new string("world");
    s1.intern();
    string s2 = "hello world";
    system.out.println(s1 == s2);   //true
}

第一行代码string s1 = new string("hello ") + new string("world");的执行过程是这样子的:

  1. 依次在堆内存中创建hello和world两个字符串对象;
  2. 然后把它们拼接起来 (底层使用stringbuilder实现);
  3. 在拼接完成后会产生新的hello world对象,这时变量s1指向新对象hello world。

执行完第一行代码后,内存是这样子的:

详细图解Java中字符串的初始化

第二行代码s1.intern();

当调用intern()方法时,首先会去常量池中查找是否有该字符串对应的引用,如果有就直接返回该字符串;

如果没有,就会在常量池中注册该字符串的引用,然后返回该字符串。

由于第一行代码采用的是new的方式创建字符串,所以在字符串常量池中没有保存hello world对应的引用,虚拟机会在常量池中进行注册,注册完后的内存示意图如下:

详细图解Java中字符串的初始化

第三行代码string s2 = "hello world";

首先虚拟机会去检查字符串常量池,发现有指向hello world的引用。然后把该引用所指向的字符串直接返回给所属变量。

执行完第三行代码后,内存示意图如下:

详细图解Java中字符串的初始化

如图所示,s1和s2指向的是相同的对象,所以当判断s1 == s2时返回true。

总结:

  • 当用new关键字创建字符串对象时,不会查询字符串常量池;
  • 当用双引号直接声明字符串对象时,虚拟机将会查询字符串常量池。

说白了就是:字符串常量池提供了字符串的复用功能,除非我们要显式创建新的字符串对象,否则对同一个字符串虚拟机只会维护一份拷贝。

反编译代码验证字符串初始化操作

下面我们再来看一个示例:

?
1
2
3
4
5
6
7
8
9
public class main {
    public static void main(string[] args) {
        string s1 = "hello ";
        string s2 = "world";
        string s3 = s1 + s2;
        string s4 = "hello world";
        system.out.println(s3 == s4);
    }
}

首先第一行和第二行是常规的字符串对象声明,它们分别会在堆内存创建字符串对象,并会在字符串常量池中进行注册。

影响我们做出判断的是第三行代码string s3 = s1 + s2;,我们不知道s1 + s2在创建完新字符串hello world后是否会在字符串常量池进行注册。

简单点说:我们不知道这行代码是以双引号形式声明字符串,还是用new关键字创建字符串。

那么我们看下这端代码的反编译后的代码:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
ps d:\code\javase\target\classes\demo> javap -c .\main.class
compiled from "main.java"
public class demo.main {
  public demo.main();
    code:
       0: aload_0
       1: invokespecial #1                  // method java/lang/object."<init>":()v
       4: return
 
  public static void main(java.lang.string[]);
    code:
       0: ldc           #2                  // string hello
       2: astore_1
       3: ldc           #3                  // string world
       5: astore_2
       6: new           #4                  // class java/lang/stringbuilder
       9: dup
      10: invokespecial #5                  // method java/lang/stringbuilder."<init>":()v
      13: aload_1
      14: invokevirtual #6                  // method java/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder;
      17: aload_2
      18: invokevirtual #6                  // method java/lang/stringbuilder.append:(ljava/lang/string;)ljava/lang/stringbuilder;
      21: invokevirtual #7                  // method java/lang/stringbuilder.tostring:()ljava/lang/string;
      24: astore_3
      25: ldc           #8                  // string hello world
      27: astore        4
      29: getstatic     #9                  // field java/lang/system.out:ljava/io/printstream;
      32: aload_3
      33: aload         4
      35: if_acmpne     42
      38: iconst_1
      39: goto          43
      42: iconst_0
      43: invokevirtual #10                 // method java/io/printstream.println:(z)v
      46: return
}

直接看重点:

  • 21: invokevirtual #7 // method java/lang/stringbuilder.tostring:()ljava/lang/string;
  • 24: astore_3
  • 虚拟机调用stringbuilder的tostring()方法获得字符串hello world,并存放至s3。

下面是我们追踪stringbuilder的tostring()方法源码:

?
1
2
3
4
5
@override
public string tostring() {
    // create a copy, don't share the array
    return new string(value, 0, count);
}

通过以上源码可以看出:s3是通过new关键字获得字符串对象的。

回到题目,也就是说字符串常量表中没有存储hello world的引用,当s4以引号的形式声明字符串时,由于在字符串常量池中查不到相应的引用,所以会在堆内存中新创建一个字符串对象。 所以s3和s4指向的不是同一个字符串对象, 结果为false。

总结

到此这篇关于java中字符串初始化的文章就介绍到这了,更多相关java字符串的初始化内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://juejin.cn/post/7000236699317960711

延伸 · 阅读

精彩推荐
  • Java教程Java BufferWriter写文件写不进去或缺失数据的解决

    Java BufferWriter写文件写不进去或缺失数据的解决

    这篇文章主要介绍了Java BufferWriter写文件写不进去或缺失数据的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望...

    spcoder14552021-10-18
  • Java教程升级IDEA后Lombok不能使用的解决方法

    升级IDEA后Lombok不能使用的解决方法

    最近看到提示IDEA提示升级,寻思已经有好久没有升过级了。升级完毕重启之后,突然发现好多错误,本文就来介绍一下如何解决,感兴趣的可以了解一下...

    程序猿DD9332021-10-08
  • Java教程xml与Java对象的转换详解

    xml与Java对象的转换详解

    这篇文章主要介绍了xml与Java对象的转换详解的相关资料,需要的朋友可以参考下...

    Java教程网2942020-09-17
  • Java教程Java8中Stream使用的一个注意事项

    Java8中Stream使用的一个注意事项

    最近在工作中发现了对于集合操作转换的神器,java8新特性 stream,但在使用中遇到了一个非常重要的注意点,所以这篇文章主要给大家介绍了关于Java8中S...

    阿杜7482021-02-04
  • Java教程小米推送Java代码

    小米推送Java代码

    今天小编就为大家分享一篇关于小米推送Java代码,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧...

    富贵稳中求8032021-07-12
  • Java教程Java实现抢红包功能

    Java实现抢红包功能

    这篇文章主要为大家详细介绍了Java实现抢红包功能,采用多线程模拟多人同时抢红包,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙...

    littleschemer13532021-05-16
  • Java教程20个非常实用的Java程序代码片段

    20个非常实用的Java程序代码片段

    这篇文章主要为大家分享了20个非常实用的Java程序片段,对java开发项目有所帮助,感兴趣的小伙伴们可以参考一下 ...

    lijiao5352020-04-06
  • Java教程Java使用SAX解析xml的示例

    Java使用SAX解析xml的示例

    这篇文章主要介绍了Java使用SAX解析xml的示例,帮助大家更好的理解和学习使用Java,感兴趣的朋友可以了解下...

    大行者10067412021-08-30