重学Java-基础篇-String

369 阅读4分钟

String 字符串对象

创建字符串的方式

String是Java中一个不可变的类,所以他一旦被实例化就无法被修改。不可变类的实例一旦创建,其成员变量的值就不能被修改。这样设计有很多好处,比如可以缓存hashcode、使用更加便利以及更加安全等。

String s ="JAVA"; String b = new String("JAVA");

两种创建方式的区别:初始化的时候可能创建了一个对象,也可能一个对象也没有创建;后者因为new关键字,至少在内存中创建了一个对象,也有可能是两个对象。

String s ="JAVA"; 在编译期,JVM会去常量池查找是否存在“JAVA”,如果不存在,就在常量池中开辟一个空间来存储“JAVA”;如果存在,就不用新开辟空间。然后在栈内存中开辟一个名字为JAVA的空间,来存储“abc”在常量池中的地址值。

String b = new String("JAVA"); 在编译阶段JVM先去常量池中查找是否存在“JAVA”,如果过不存在,则在常量池中开辟一个空间存储“JAVA”。在运行时期,通过String类的构造器在堆内存中new了一个空间,然后将String池中的“JAVA”复制一份存放到该堆空间中,在栈中开辟名字为b的空间,存放堆中new出来的这个String对象的地址值。

不可边的好处

1. 可以缓存 hash 值

因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。

2. String Pool 的需要

如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。

3. 安全性

String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。

4. 线程安全

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

著作权归pdai.tech所有。 链接:pdai.tech/md/java/bas…

String, StringBuffer and StringBuilder

1. 可变性

  • String 不可变
  • StringBuffer 和 StringBuilder 可变

2. 线程安全

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

String.intern()

使用 String.intern() 可以保证相同内容的字符串变量引用同一的内存对象。

下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同对象,而 s3 是通过 s1.intern() 方法取得一个对象引用。intern() 首先把 s1 引用的对象放到 String Pool(字符串常量池)中,然后返回这个对象引用。因此 s3 和 s1 引用的是同一个字符串常量池的对象。

        String b = new String("ss");
        System.out.println(a==b); //false     
        String c= a.intern();
        // a.intern()  获取当前对象引用地址 
        System.out.println(a==c.intern()); // true

采用""的方式创建字符串实例,会自动地将新建的对象放入 String Pool 中。

String a = "ss";
String b = "ss";    
System.out.println(a==b); // true

字符串存放位置

在JVM中,为了减少相同的字符串的重复创建,为了达到节省内存的目的。会单独开辟一块内存,用于保存字符串常量,这个内存区域被叫做字符串常量池。

在JDK 7以前的版本中,字符串常量池是放在永久代中的。因为按照计划,JDK会在后续的版本中通过元空间来代替永久代,所以首先在JDK 7中,将字符串常量池先从永久代中移出,暂时放到了堆内存中。

在JDK 8中,彻底移除了永久代,使用元空间替代了永久代,于是字符串常量池再次从堆内存移动到永久代中

字符串长度限制

字符串有长度限制,在编译期,要求字符串常量池中的常量不能超过65535,并且在javac执行过程中控制了最大值为65534。在运行期,长度不能超过Int的范围,否则会抛异常。

hollischuang.gitee.io/tobetopjava…

字符串的拼接方式

字符串的拼接方式有,+、concat,或者使用 StringUtils.join 、 StringBuffer和StringBuilder替代 。

hollischuang.gitee.io/tobetopjava…