String类的特点

    技术2022-08-03  96

    String类的特点是什么?


    概览

    String 被声明为 final,因此它不可被继承。(Integer 等包装类也不能被继承) 在java8中,String内部以char[]数组的形式存储数据;

    public final class String implements java.io.Serializable, Comparable<String>, CharSequence { /** The value is used for character storage. */ private final char value[];

    String 常见的创建方式:

    String s1 = “java”; 从String pool寻找,返回句柄String s2 = new String(“java”)

    第一种方式,从String pool寻找java,没有则在pool中创建,返回句柄; 第二种方式,会直接在堆(1.7后)创建String对象,只有调用了intern()方法,才会放入String pool; [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SYCt7EBY-1593684383098)(/home/picture/1.png)] JDK 1.7 之后把永生代换成的元空间,把字符串常量池从方法区移到了 Java 堆上。 除此之外编译器还会对String字符串做一些优化:

    String s1 = "ja"+"va"; String s2 = "java"; System.out.pringln(s1 == s2); //结果为true

    不可变

    value数组被生命成了final,意味着value一旦初始化后便不可指向其它内存地址,并且String内部,没有改变value内容的任何方法。且String类为final类,避免了子类重写或修改String对象属性; 保护性拷贝:

    public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }

    这是以char数组为参数的一个构造方法,它并没有把这个数组引用直接赋值给实例对象的value成员变量,而是通过一个Arrays.copyOf的方式拷贝一个数组再给到对象的成员变量,防止外部引用执行同一个地址而修改该数组内容。

    不可变的好处

    1.Requirement of String Pool

    如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。 以下代码将在堆中仅创建一个字符串对象。

    字符串 string1 = “ abcd” ; 字符串 string2 = “ abcd” ;

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-X4Nu5xMj-1593684383101)(/home/picture/1.png)]

    2.Caching Hashcode(缓存HashCode)

    字符串的哈希码在Java中经常使用。例如,在HashMap或HashSet中。不可变保证哈希码始终是相同的,这意味着无需每次使用哈希码就进行计算,这样更有效。

    3.安全

    字符串被广泛用作许多java类的参数,例如网络连接,打开文件等。如果字符串不是不可变的,则连接或文件将被更改,这可能会导致严重的安全威胁,可变字符串也可能在反射中引起安全问题。

    4.线程安全

    String 不可变性天生具备线程安全,可以在多个线程中安全地使用。

    String pool

    字符串常量池保存着所有字符串字面量,这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程将字符串添加到 String Pool 中。 主要使用方式:

    直接使用双引号声明出来的String对象会直接存储在常量池中。如果不是用双引号声明的String对象,可以使用String提供的intern方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中 String s1 = "aaa"; String s2 = "aaa"; System.out.println(s1 == s2); // true

    如果采用"aaa"这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。 intern() 方法:当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。

    它的大体实现结构就是: JAVA 使用 jni 调用c++实现的StringTable的intern方法, StringTable的intern方法跟Java中的HashMap的实现是差不多的, 只是不能自动扩容。默认大小是1009。 要注意的是,String的String Pool是一个固定大小的Hashtable,默认值大小长度是1009,如果放进String Pool的String非常多,就会造成Hash冲突严重,从而导致链表会很长,而链表长了后直接会造成的影响就是当调用String.intern时性能会大幅下降(因为要一个一个找)。

    在 jdk6中StringTable是固定的,就是1009的长度,所以如果常量池中的字符串过多就会导致效率下降很快。在jdk7中,StringTable的长度可以通过一个参数指定:

    -XX:StringTableSize=99991

    new String(“abc”) 上述的语句中是创建了2个对象,第一个对象是”abc”字符串存储在常量池中,第二个对象在JAVA Heap中的 String 对象。

    String, StringBuffer and StringBuilder

    1. 可变性 String 不可变 StringBuffer 和 StringBuilder 可变 2. 线程安全 String 不可变,因此是线程安全的 StringBuilder 不是线程安全的 StringBuffer 是线程安全的,内部使用 synchronized 进行同步

    常用方法

    1. equals() 用于比较两个字符串是否相等,比较时会先通过instanceof 判断是否为String类型,如果不是直接反悔false,否则循环比较每一个字符

    Processed: 0.014, SQL: 9