String类的特点

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,否则循环比较每一个字符

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值