字符串常量:String、StringBuffer和StringBuilder的区别?

发布于:2023-01-23 ⋅ 阅读:(542) ⋅ 点赞:(0)

String 字符串

String类 是被 final关键字 声明的,因此它不可被继承。 String 字符串是引用类型,底层用 char 数组实现的。

String 字符串的特点:

        1.字符串不可变,它们的值在创建后不能被更改。

        2.虽然String 的值是不可变的,但是可以被共享 字符串效果上相当于字符数组( char[] ),但是底层原理是字节数组( byte[] )。

String 字符串解析:

        1.通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,即使内容相同,但地址值不同。

        2.以“”方式给出的字符串,JVM会将其存放在 字符串常量池 中维护。

        3.且若多个“”方式给出的字符序列(顺序及大小写)相同,JVM只会建立一个String 对象。

为什么 String 字符串 不适用于 大量 字符串 拼接 操作?

String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,对内存空间的极大浪费。

String 字符串的 + 操作(字符串 拼接 操作)其本质是创建了 StringBuilder 对象进行 append() 操作,然后将拼接后的 StringBuilder 对象用 toString() 方法处理成 String 对象。

在 Java 中无论使用何种方式进行字符串连接,实际上都使用的是 StringBuilder。

我们知道,在Java中有两种创建字符串对象的方式:

  1. 采用字面值的方式赋值。
  2. 采用new关键字 新建一个字符串对象。

String str = new String("abc")创建了几个对象?

创建2个对象。

第一个对象是”abc”字符串 存储 在字符串常量池中;

第二个对象在JAVA Heap堆 中 new 的 String 对象

String str = "a" + "b" + "c" 创建了几个对象?

创建1个对象。

因为 赋值符号右边的"a"、"b"、"c"都是常量

String str = new String("a") + new String("b")创建了几个对象?

创建6个对象。

        对象1:new StringBuilder()

        对象2:new String("a")

        对象3:常量池的 a

        对象4:new String("b")

        对象5:常量池的 b

        对象6:toString中会创建一个 new String("ab")

String str= "abc";
final String finalStr = "abc";//final修饰的是常量

String str1 = "abc01";    
        
String str2 = "abc" + "01";    
    
String str3 = str + "01";    
    
String str4 = finalStr + "01";   
 
String str5 = new String("abc01").intern();    


System.out.println(str1 == str2);    // true
System.out.println(str1 == str3);    // false
System.out.println(str1 == str4);    // true   //final修饰的是常量
System.out.println(str1 == str5);    // true

String、StringBuffer 和 StringBuilder 的区别

1)、可变不可变

String:字符串常量,在修改时不会改变自身;若修改,等于重新生成新的字符串对象。
StringBuffer:字符串变量,在修改时会改变对象自身,每次操作都是对 StringBuffer 对象本身进行修改,不是生成新的对象;
使用场景:对字符串经常改变情况下,主要方法:append(),insert()等。

2)、线程是否安全

String:对象定义后不可变,线程安全。
StringBuffer:是线程安全的(对调用方法加入synchronized同步锁),执行效率较慢,适用于多线程下操作字符串缓冲区大量数据。
StringBuilder:是线程不安全的,StringBuilder 效率高于 StringBuffer,适用于单线程下操作字符串缓冲区大量数据。

3)、共同点

StringBuilder 与 StringBuffer 有公共父类 AbstractStringBuilder(抽象类)
StringBuilder、StringBuffer 的方法都会调用 AbstractStringBuilder 中的公共方法,只是StringBuffer 会在方法上加 synchronized 关键字,进行同步。
最后,如果程序不是多线程的,那么使用 StringBuilder 效率高于 StringBuffer。

String

不可变字符串 线程安全 每次new 都是生成新的String对象 不适用于 大量 字符串 拼接 操作,影响内存性能

StringBuffer

可变字符串 线程安全 StringBuffer 执行效率慢 适用于多线程下操作字符串缓冲区大量数据

StringBuilder

可变字符串 线程不安全 StringBuilder 执行效率高 适用于单线程下操作字符串缓冲区大量数据

常量

final修饰的成员变量表示常量,值一旦给定就无法改变!

final修饰的变量分别表示三种类型的常量:静态变量、实例变量 和 局部变量。

Java中的常量池,实际上分为两种形态:静态常量池 和 运行时常量池

    1)静态常量池,即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间。

    2)运行时常量池,则是JVM虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。

常量池(Constant Pool)

常量池,也叫 Class 常量池(常量池==Class常量池,Class Constant Pool)。Java文件被编译成 Class文件,Class文件中除了包含类的版本、字段、方法、接口等描述信息外,还有一项就是常量池,每个class文件都有一个class常量池。常量池是当Class文件被Java虚拟机加载进来后存放在方法区 各种 字面量 (Literal)符号引用(SymbolicReferences)

字面量 包括:1.文本字符串 2.八种基本类型的值 3.被声明为final的常量等;

符号引用 包括:1.类和方法的全限定名 2.字段的名称和描述符 3.方法的名称和描述符。

运行时常量池(Runtime Constant Pool)

运行时常量池是方法区的一部分。运行时常量池是当Class文件被加载到内存后,Java虚拟机会 将Class文件常量池里的内容转移到运行时常量池里(运行时常量池也是每个类都有一个)。运行时常量池相对于Class文件常量池的另外一个重要特征是具备动态性,Java语言并不要求常量一定只有编译期才能产生,也就是并非预置入Class文件中常量池的内容才能进入方法区运行时常量池,运行期间也可能将新的常量放入池中

字符串常量池(String Constant Pool)

字符串常量池又称为:字符串池,全局字符串池,英文也叫String Constant Pool。

字符串常量池是全局的,JVM中独此一份,因此也称为全局字符串常量池

String的String Pool是一个固定大小的Hashtable,默认值大小长度是1009。

在工作中,String类是我们使用频率非常高的一种对象类型。JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,这就是我们今天要讨论的核心:字符串常量池。字符串常量池由String类私有的维护

class常量池 是在编译的时候每个class都有的. 在编译阶段,存放的是常量的 符号引用 。       [在class文件中]


字符串常量池 在每个VM中只有一份,存放的是字符串常量的 引用值 。  [在堆中]              


运行时常量池 是在类加载完成之后,将每个class常量池 中的符号引用值转存到 运行时常量池 中,也就是说,每个class都有一个 运行时常量池 ,类在 解析阶段 ,将 符号引用 替换成 直接引用 ,与 字符串常量池 中的引用值保持一致。[在方法区]  

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到