String 对象是对 char 数组进行了封装实现的对象,主要有两个成员:char 数组,hash 值

String 对象的不可变性

     在实现代码中 String 类被final 关键字修饰了,而且变量 char 数组也被 final 修饰了。都知道类被final 修饰代表该类不可继承,而 char[] 被 final+private 修饰,代表 String 对象不可被更改。Java 实现了这个特性叫做 String 对象的不可变性,即 String 对象一旦创建成功,就不能再对它进行改变

 

这样做的好处是什么?

  1. 保证 String 对象的安全性,假设String 对象是可变的,那么 String 对象将可能被恶意修改
  2. 保证 hash 属性值不会被频繁变更,确保了唯一性,使得类似 HashMap 容器才能实现响应的 key-value 缓存功能
  3. 可以实现字符串常量池。在 Java 中,通常有两种字符串创建方式,一种通过字符串的方式创建,如 String str = “abc”,另一种是通过 new 的方式创建,如 String str = new String("abc)

 

String 的创建方式及内存分配的方式

1、String str = “abc”;

        当代码中使用这种方式创建字符串对象是,JVM 首先会检查该对象是否在字符串常量池中,如果在,那么就返回该字符串的引用,否则新字符串就会再常量池进行创建。这种方式可以减少同一个值的字符串的重复创建,节约内存(str 只是个引用)

 

2、String str = new String("abc")

首先在编译类文件时,“abc”常量字符串会被放入进常量结构中,在类加载时“abc”将会在常量池进行创建,其次,在调用new 时,JVM命令将会调用 String 的构造函数,同时引用常量池中的“abc” 字符串,在堆内存中创建一个String对象,最后 str 将引用 String 对象

3、使用new ,对象会创建在堆里,同时赋值的话,会在常量池中创建一个字符串对象,复制到堆中。

具体的赋值过程是现将常量池中压入栈中,在使用 String 的构造方法时,会拿到栈中的字符串做为构造函数的参数。

这个构造函数式一个 char数组的赋值过程,而不是new 出来的,所以是引用常量池中的字符串对象,存在引用关系

public class Location {
    private String city;
    private String region;
}

4、String str = "ab"+"cd"+"ef";

在编码过程中,字符串的拼接很常见。前面说过 String 对象是不可变的,如果我们使用String对象相加,拼接想要的字符串,会不会产生多个对象呢?例如代码:String str = "ab"+"cd"+"ef";

分析代码可以知道:首先会变成 ab 对象,在生成 abcd 对象,最后生成 abcdef 对象,从理论上来说,这段代码是低效的。

但是编译器会在编译的时候会自动优化这段代码,优化为:String str= "abcdef";

 

5、大循环使用

intern

      String 的 intern 方法,如果常量池中有相同值,就会重复使用该对象,返回对象的引用。

  1. new String()会在内存中创建一个 a 的 String 对象 , king 在常量池中创建
  2. 在调用 intern方法之后,会在常量池中查找是否有等于该字段对象的引用,有就返回引用。
  3. 调用 new String()会在堆内存中创建一个 b 的 String 对象
  4. 在调用 intern 方法之后,回去常量池中查找是否有等于该字符串的引用,有就返回引用

所以 a 和 b 引用的是同一个对象

 

 

 

 

 

最后修改于 2020-07-23 16:09:04
如果觉得我的文章对你有用,请随意赞赏
扫一扫支付
上一篇