第二节: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”对象,所以也直接返回- 故
s2
和s1
的地址相同。所以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的主要内容,如果未能解决你的问题,请参考以下文章