栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java随笔-String

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java随笔-String

String

字符串是Java开发中使用最多的数据类型之一,但不属于8种基本数据类型,属于对象。了解字符串的使用原理有助于写出高质量的代码。

源码

String类在JDK的发展过程中也不是一成不变的,其中JDK1.8升级至JDK1.9时变化稍微大一些。

JDK1.8

public final class String
    implements java.io.Serializable, Comparable, CharSequence
{
    
    private final char value[];
    ...
}

JDK1.9+

public final class String
    implements java.io.Serializable, Comparable, CharSequence,
               Constable, ConstantDesc {
    @Stable
    private final byte[] value;
    private final byte coder;
    ...
    static final boolean COMPACT_STRINGS;

    static {
        COMPACT_STRINGS = true;
    }
  }
    比较发现String存储由原来的char value[ ]变成了byte[ ] value,这是因为字符串中拉丁字母居多,使用char存储时占用两个字节,大多数情况下会造成一个字节的浪费,空间浪费增加GC被触发的概率,而byte只占用一个字节,会减少空间浪费。若是存储汉字会用到两个字节,此时字节码标识符coder和字符串压缩COMPACT_STRINGS就发挥重要作用。String类是final类,不能被继承。存储使用char value[ ]或byte[ ] value也是final,也就是String一旦被创建就无法修改,所有改变属性的操作均会产生新的对象。Java中String使用最频繁,String创建后一般会保存在堆中,而堆是可以被多线程共享的,这样做不安全,final则解决了安全问题。基本数据类型的包装对象和String类一样,都是不可修改的。
存储与使用 存储


常量池主要分为:class常量池、运行时常量池。使用字符串时编译时,首先会将字符串放在字符串常量池中,但是字符串常量池只是民间的一种说法,官方文档中没有,具体存储的位置有可能在常量池中,也有可能在堆中。String在使用时,首先会把字符串放入字符串常量池中,若是字面量,则直接使用,若是创建对象,则返回堆中对象引用。

字面量
    // 字面量
    String str = "abc";

代码编译时会直接在常量池中创建"abc",运行时会直接从字符串常量池中返回"abc"的引用。

字面量使用简单,不用在堆中创建对象,直接返回引用,推荐使用该方法使用字符串。

创建对象
    // 创建对象
    String str = new String("abc");

使用new创建字符串对象时,一般分两步:
1,代码编译时,在字符串常量池中创建"abc"’;
2,使用new时,在堆中创建str对象,并引用字符串常量池的"abc",并返回str的引用。

虽然所使用字面量和使用new创建对象效果相同:

但是使用new需要在堆中创建str对象并返回对象引用,有点浪费空间,一般没有特别要求,不建议使用该方法创建字符串。

优化 为什么要使用字符串常量池

使用new创建字符串对象。

若是使用new创建String对象,虽str1 != str2,但是两者都指向字符串常量池中的"abc"。如何验证,调用intern()可直接获取字符串常量池内容。

        // 创建对象
        String str1 = new String("abc");
        String str2 = new String("abc");

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

结果:

说明str1和str2是两个对象,但两者字符串引用相同。
若是知道要使用的字符串在字符串常量池中已经存在,可以调用intern()直接从字符串常量池中取值再赋值。

        // 创建对象
        String str2 = new String("abc");
        String str5 = str2.intern();
        System.out.println(str5);

结果:

abc

使用字面量同样引用同一块"abc"。

        // 字面量
        String str = "abc";
        String str1 = "abc";
        System.out.println(str == str1);

结果:

说明:

说明若是内容相同,则后创建的对象会直接使用常量池中的内容。
总而言之,字符串常量池不管有没有这个说法,但是若内容字符串已存在,后续使用则不会创建新对象,会直接取已存在的字符串,这样做效率更高,节省资源,毕竟String使用频率如此之高。

纯字符串拼接
    // 纯字符穿拼接
    String strPlus = "a" + "b" + "c";

像代码中纯字符串拼接的情况不会出现在理智的代码中,但是出现了也不会有影响,编译器会自动优化成:

    // 纯字符穿拼接
    String strPlus = "abc";

验证:

        // 字面量
        String str = "abc";
        // 字符穿拼接
        String strPlus = "a" + "b" + "c";
        System.out.println(str == strPlus);

结果:

多字符串拼接
        // 多字符串拼接
        String strAdd = new String();
        for (int i = 0; i < 1000; i++) {
            strAdd = strAdd + i;
        }

上述代码会在编译时自动优化成:

        // 多字符串拼接自动优化
        for (int i = 0; i < 1000; i++) {
            strAdd = new StringBuilder(strAdd).append(i).toString();
        }

这样会减少对象的创建,提高拼接速度。若是需要拼接的字符串比较少,还是建议使用"+"进行拼接,此时拼接效率要比StringBuilder拼接效率高。
若是字符串拼接有关于其他对象的引用,则编译器不会做优化。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/749073.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号