第二节:Java字符串常量池和StringBuilder

Posted 快乐江湖

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第二节:Java字符串常量池和StringBuilder相关的知识,希望对你有一定的参考价值。

文章目录

一:字符串常量池

(1)池化技术

池化技术:池化技术 (Pool) 是一种很常见的编程技巧,在请求量大时能明显优化应用性能,降低系统频繁建连的资源开销。我们日常工作中常见的有数据库连接池、线程池、对象池等,它们的特点都是将 “昂贵的”、“费时的” 的资源维护在一个特定的 “池子” 中,规定其最小连接数、最大连接数、阻塞队列等配置,方便进行统一管理和复用,通常还会附带一些探活机制、强制回收、监控一类的配套功

在Java中,为了节省存储空间和提升程序的运行效率,引入了

  • Class文件常量池:每个.java源文件编译生成的.class文件中会保存当前类中的字面常量以及符号信息
  • 运行时常量池:在.class文件被加载时,.class文件中的常量池被加载到内存中称为运行时常量池,每个类都有一份
  • 字符串常量池:(下面介绍)

(2)字符串常量池(StringTable)

  • Java为8种基本数据类型和String类都提供了常量池

字符串常量池(StringTable):字符串常量池在JVM中是一个StringTable类(其本质是一个固定大小的HashTable)

(3)再看String对象创建

  • 之前学习String类的创建时,我们仅仅是从语法上进行了学习

A:字面常量直接赋值

当我们在程序中使用双引号来表示一个字符串时,JVM会到字符串常量池查找 “aaa” 这个字面量对象是否存在?

  • 存在:则返回该对象的引用给变量 str1

  • 不存在:则在堆中创建一个相应的对象,将创建的对象的引用存放到字符串常量池中,同时将引用返回给变量 str1

所以下面str1和str2实际上是一个对象

public class TestDemo 
    public static void main(String[] args) 
        String str1 = "aaa";
        String str2 = "aaa";
        System.out.println(str1 == str2);
    

B:通过new创建String对象

当我们使用了new 来构造字符串对象的时候,不管字符串常量池中是否有相同内容的对象的引用,新的字符串对象都会创建

如下,str3和str4虽然值一样,但他们是不同的对象

public class TestDemo 
    public static void main(String[] args) 
        String str1 = "hello";
        String str2 = "hello";
        String str3 = new String("world");
        String str4 = new String("world");
        System.out.println(str3==str4);
    

C:intern()方法

intern()方法可以手动将创建的String对象添加到常量池中

  • 当调用这个方法时,会去检查字符串常量池中是否已经存在这个字符串,如果存在的话,就直接返回,如果不存在的话,就把这个字符串常量加入到字符串常量池中,然后再返回其引用
    public static void main(String[] args) 
        String s = new String("hello");//两个对象,一个在堆中,一个在常量池中
        String s1 = s.intern();//检查常量池中是否存在“hello”,这里存在所以直接返回引用
        String s2 = "hello";

        System.out.println(s == s2);
        System.out.println(s1 == s2);
    

具体过程如下

  • new String("hello"):会在字符串常量池中创建一个"hello"对象,同时也会在堆中创建一个"hello"对象,然后使s的引用指向堆中的这个"hello"对象
  • String s1 = s.intern():由于字符串常量池中已经存在"hello"对象,所以直接返回其引用,此时s1的引用指向字符串常量池中的"hello"对象
  • String s2 = "hello"; 此时字符串常量池中已经存在“hello”对象,所以也直接返回
  • s2s1 的地址相同。所以 s1 == s2 返回 true

二:字符串的不可变性

String类在设计时,其字符被保存到了内部维护的value字符数组中,外部是无法拿到这个数组的

  • String类被final修饰,表明该类不能被继承
  • value被修饰被final修饰,表明value自身的值不能改变,即不能弓|用其它字符数组,但是其引用空间中的内容可以修改

三:字符串的修改

(1)直接修改

尽量要避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下

例如下面的代码,虽然可以达到最终的目的,但是其效率十分低下,执行过程中创建了很多临时对象

  public static void main(String[] args) 
      String s = "hello";
      s += "world";
      System.out.println(s);
  

(2)StringBuilder和StringBuffer

由于String的不可更改造成的一些困难,,因此Java中提供了StringBuilder和StringBuffer这两个类以方便字符串的修改

常用方法如下

方法功能
StringBuilder append(String str)尾部追加,相当于String中的“+=
char charAt(int index)获取index位置处的字符
int length()获取字符串长度
int capacity获取底层保存字符串空间总大小
void ensureCapacity(int mininmumCapacity)扩容
void setCharAt(int index, char ch )index位置处的字符设置为ch
int indexOf(String str)返回str第一次出现的位置
int indexOf(String str, int fromIndex)fromIndex位置开始查找str第一次出现的位置
int lastIndexOf(String str)返回str最后一次出现的位置
int lastIndexOf(String str, int fromIndex)fromIndex位置开始查找str最后一次出现的位置
StringBuilder insert(int offset, String str)offset位置插入str
StringBuilder deleteCharAt(int index)删除index位置处字符
String Builder delete(int strat, int end)删除[start, end)内的字符
StringBuilder repalce(int star, int end, String str)[start, end) 内的字符替换为str
String substring(int start, int end)[start, end) 范围内的字符以String返回
StringBuilder reverse()反转字符串
String toString所有字符串按String返回

以上是关于第二节:Java字符串常量池和StringBuilder的主要内容,如果未能解决你的问题,请参考以下文章

字符串常量池和String::intern()的讨论

字符串常量池和String::intern()的讨论

36Java 中的 StringStringBuilderStringBuffer字符串常量池和 intern 方法

Java运行时常量池是啥?

第二节:Python的变量常量

Jave运行时常量池是啥意思?