转载

String,你真的了解吗?

不管是Java语言还是C/C++语言,String可以说是我们用的最多的类型吧!但是你是否真的了解它呢?那下面咱们一起聊聊Java String吧!

String常量

JDK版本不同,字符串常量所处的JVM位置不同,关于 虚拟机运行时数据区 ,后续专门找一个机会来分享;

  • 版本<=JDK 1.6:字符串常量池--永久代;
  • 版本>=JDK 1.7:字符串常量池--堆;

备注:本文示例JDK环境: JDK 1.8 示例代码

String.intern

返回标准表示的字符串对象。String类维护私有字符串池。 调用此方法时,如果字符串池已经包含等于此字符串对象的字符串(通过equals方法确定), 则返回池中的字符串。 否则,将此String对象添加到池中,并返回对此String对象的引用。 这个功能为String提供了字符串池,我们可以使用它来优化内存。但是,这有一个缺点:在OpenJDK中,String.intern()是本地方法,它实际上调用了JVM的相关方法来实现该功能。

public static void main(String args[]) {
        String s1 = new String("hello") + new String(" java");
        s1.intern();
        String s2 = "hello java";
        System.out.println("s1.intern()==s2: " + (s1.intern()==s2));  
        System.out.println("s1==s2: " + (s1==s2));
        String s3 = new String("hello");
        s3.intern();
        String s4 = "hello";
        System.out.println("s3.intern()==s4: " + (s3.intern()==s4));  
        System.out.println("s3==s4: " + (s3==s4)); 
    }
复制代码

输出结果:

s1.intern()==s2: true
s1==s2: true
s3.intern()==s4: true
s3==s4: false
复制代码

说明:

第一行代码:共计创建五个对象:2个字符串常量对象,3个堆对象,其中"hello java"堆对象是最终的需要的对象;

第二行代码:执行intern,首先去常量池查找,如果没有找到,则原则上需要在常量池创建一份s1数据的拷贝,但是由于JDK8常量池并入了Heap上,因此,不会再创建一份s1数据的拷贝,直接创建一份引用指向s1,保存到常量池中。

第三行代码:显示声明一个字符串常量对象,由于常量池中已经存在,则直接和常量池一样,指向s1;

所以,无论s1,s1.intern()和s2都指向同一个对象,因此,s1=s2=s1.intern();

第六行代码:执行完,创建两个对象,一个在heap,一个在常量池;

第七行代码:执行s3.intern()时,由于常量池中已经创建了此对象(在执行第六行的时候创建的),因此执行s3.intern(),则不做任何处理;

第八行代码:显示声明一个字符串常量对象,由于常量池中已经存在,则直接指向常量池中的对象;

所以:s3.intern()指向常量池中的对象,s4则也指向常量池,s3.intern() = s4;s3指向堆中的对象,则s3 != s4;

具体的对象关系如下图:

String,你真的了解吗?

)

String, StringBuffer, StringBuilder

String StringBuffer StringBuilder
String的值是不可变的,这就导致每次 对String的操作都会生成新的String对象, 不仅效率低下,而且浪费大量优先的内存空间 StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。每个StringBuffer对象都有一定的缓冲区容量,当字符串大小没有超过容量时,不会分配新的容量,当字符串大小超过容量时,会自动增加容量 可变类,速度更快
线程安全 线程不安全
多线程操作字符串 单线程操作字符串

String用到的“+”号

在Java中的String类已经重载的"+",因此String支持“+”,通过反编译的字节码来看,其实是通过创建StringBuilder来完成字符串拼接;

这里具体说明:如果在for循环内部,不建议使用“+”的方式来进行字符串的拼接,会增加系统的开销。此处顺便回答了颠倒语序如何实现?中的一个遗留问题!

public static void test_string_builder()
    {
        long start = System.currentTimeMillis();
        Random rand = new Random();
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < 1000; i++)
        {
            res.append(rand.nextInt(10));
            res.append(" ");
        }
        System.out.println(res.toString());
        long end = System.currentTimeMillis();
        System.out.println("test_string_builder cost: " + (end - start));
    }
复制代码
时间成本: test_string_builder cost: 1
复制代码
public static void test_string_plus()
    {
        long start = System.currentTimeMillis();
        Random rand = new Random();
        String res = "";
        for (int i = 0; i < 1000; i++)
        {
            res += rand.nextInt(10);
            res += " ";
        }
        System.out.println(res.toString());
        long end = System.currentTimeMillis();
        System.out.println("test_string_plus cost: " + (end - start));
    }
复制代码
时间成本:test_string_plus cost: 6
复制代码
原文  https://juejin.im/post/5ee5d191e51d4578787bbc41
正文到此结束
Loading...