第1节 常用类库——String

因为String相对之前的类来说更加常用一些,所以对字符串类进行专门的整理。

1. 概述

String类表示字符串,Java中的所有字符串文字都实现为此类的实例。

字符串是不变的,它们的值在创建后无法更改 。因为它的创建是通过一个由private final修饰的byte数组value来实现的,一旦赋值,不可更改。

java setcontenttype 纯文本 java set string_字符串


java setcontenttype 纯文本 java set string_java_02


如果想要使用可变字符串,后面的StringBufferStringBuilder会介绍。

因为String对象是不可变的,所以可以共享它们。 这句话怎么理解?需要结合下面的赋值方式来理解。

2. String的两种赋值方式:

  • 一种为直接赋值,因为一个字符串可以表示一个String类的对象,
String text = "123";
  • 第二种为通过关键字new调用String的构造方法赋值:
String text3 = new String("123");

先来看一段代码,体会一下两者的区别:

package com.kaikeba.coreclasslibrary.string;

public class Demo {
    public static void main(String[] args) {
        String text = "123";
        String text2 = "123";
        String text3 = new String("123");
        System.out.println(text == text2);
        System.out.println(text == text3);
    }
}

结果为:
true
false

这里就用到了1中说的因为String对象是不可变的,所以可以共享它们。

因为String在内存中存储在永久代中(后续会介绍),该内存不会去进行GC,所以没有必要给同样的字符串分出两块地址,使用第一种赋值方式,并不会开辟出两块地址,而是会将两个引用对象指向同一个地址 ,所以text和text2就是一样的值,这就是共享的意思。 但是第二种赋值方式,使用new关键字强制地开辟了一块内存,所以地址值不一样。

给一张图会更直观一些,str1就是上述代码的text3,str2和str3就是上述代码的text和text2。

java setcontenttype 纯文本 java set string_字符串_03

3. 字符串常量池

3.1 方法区(Method Area)

方法区(Method Area),又称永久代(Permanent Generation),又称非堆区(Non-Heap space)。

方法区是被所有线程共享的:

    - 所有字段和方法字节码,以及一些特殊方法和构造函数,接口代码也在此定义。简单说,所有定义的方法的信息都保存在该区域,此区域属于共享区间

    - 该区域存储的是:静态变量+常量+类信息(构造方法/接口定义)+运行时常量池。

但是,实例变量(对象)存在堆内存中,和方法区无关。

以上,只是逻辑上的定义,在HotSpot中,方法区仅仅只是逻辑上的独立,实际上还是包含在Java堆中,也就是说,方法区在物理上属于Java堆区中的一部分,而永久区(Permanent Generation)就是方法区的实现。

3.2 堆(heap)

一个JVM实例只存在一个堆内存,堆内存的大小是可以调节的。类加载器读取了类文件后,需要把类、方法、常变量放到堆内存中,保存所有引用类型的真实信息,以方便执行器执行。

堆 在逻辑上分为三部分(Perm):

  • 新生代 (Young Generation,常称为YoungGen):刚创建的内存存储位置,频繁地进行GC,若一个对象连续经过15次GC还没有被回收,它就会被放到老年代。位于堆空间

    - Eden区 :存储新创建的对象;

    - Survior区 (幸存区):存储GC次数1~14次的对象。

  • 老年代 (Old Generation。常称为OldGen、TenuringGen):GC的频次较低,位于堆空间
  • 永久代 (Permanent Generation,常称为PermGen):是一个常驻内存区域,用于存放JDK自身所携带的Class、Interface的元数据,也就是说它存储的是运行环境必须的类信息,被装在进此区域的数据是不会被垃圾回收器回收的,关闭JVM才会释放此区域所占用的内存。(不进行GC,类、方法、常量、静态修饰的内容都会放在永久代位于非堆空间。

4. 构造方法

java setcontenttype 纯文本 java set string_String_04

最常用的当然还是直接给一个字符串而不是用构造器。

此外还需要注意三个构造方法:

1、构造一个新的String并用指定的解码集解码,读入不同集的字符串会需要。

java setcontenttype 纯文本 java set string_String_05

2、3:用一个StringBufferStringBuilder对象来构造String,这个可以实现StringBufferStringBuilderString类的转变。

java setcontenttype 纯文本 java set string_java_06

5. 各种方法

String类的方法很多。。。

1、返回指定索引处的char值,这还是很常用的,因为Java字符串不能像数组一样使用[索引]来访问,charAt方法就是替代。IntStream类先跳过,没学过。

java setcontenttype 纯文本 java set string_赋值_07

2、返回Unicode的方法,目前还没用过。

java setcontenttype 纯文本 java set string_字符串_08

3、按字典顺序比较两个字符串,不用多解释。

java setcontenttype 纯文本 java set string_方法区_09

4、拼接字符串,返回拼接后的结果。

java setcontenttype 纯文本 java set string_字符串_10

5、功能很明确

java setcontenttype 纯文本 java set string_方法区_11

6、字符串与字符序列或StringBuffer比较是否相等。

java setcontenttype 纯文本 java set string_赋值_12

7、判断字符串是否以指定的后缀结尾。

java setcontenttype 纯文本 java set string_String_13

8、比较是否相等

java setcontenttype 纯文本 java set string_方法区_14

9、指定的格式字符串和参数返回格式化字符串,没用过。

java setcontenttype 纯文本 java set string_String_15

10、将字符串变为数组

java setcontenttype 纯文本 java set string_java_16

11、返回字符串的哈希码

java setcontenttype 纯文本 java set string_String_17

12、返回字符第一次出现的索引

java setcontenttype 纯文本 java set string_String_18

13、啥是规范表示?

java setcontenttype 纯文本 java set string_方法区_19

14、判断字符串是否为空

java setcontenttype 纯文本 java set string_java_20

15、将字符序列按照指定的连接符拼接为字符串,这个很常用

java setcontenttype 纯文本 java set string_String_21

16、返回字符最后一次出现的索引

java setcontenttype 纯文本 java set string_String_22

17、返回字符串的长度,常用

java setcontenttype 纯文本 java set string_java_23

18、现在不懂

java setcontenttype 纯文本 java set string_赋值_24

19、判断字符串是否与指定的正则表达式匹配,没用过

java setcontenttype 纯文本 java set string_方法区_25

20、不懂

java setcontenttype 纯文本 java set string_String_26

21、判断两个字符串区域是否相等

java setcontenttype 纯文本 java set string_方法区_27

22、返回该字符串重复了count次的字符串

java setcontenttype 纯文本 java set string_java_28

23、字符串替换

java setcontenttype 纯文本 java set string_String_29

24、字符串拆分,按照指定的拆分符

java setcontenttype 纯文本 java set string_String_30

25、判断字符串是否以指定前缀开头

java setcontenttype 纯文本 java set string_字符串_31

26、去除头尾的空格

java setcontenttype 纯文本 java set string_赋值_32

27、取子字符串

java setcontenttype 纯文本 java set string_方法区_33

28、将字符串转为字符数组

java setcontenttype 纯文本 java set string_方法区_34

29、大小写

java setcontenttype 纯文本 java set string_String_35

30、和strip类似,去除的不只空格

java setcontenttype 纯文本 java set string_String_36

31、将数据类型转为字符串,注意是静态方法,直接用类名调用

java setcontenttype 纯文本 java set string_String_37

6. 字符串拼接问题

观察如下代码:

package com.kaikeba.coreclasslibrary.string;

public class Demo {
    public static void main(String[] args) {
        String t1 = "锄禾日当午";
        String t2 = "汗滴禾下土";
        String t3 = "床前明月光";
        t1 = t1+t2+t3;
        System.out.println(t1);
    }
}

它在内存中的细节如下图所示:

java setcontenttype 纯文本 java set string_字符串_38

通过“+”运算符会产生很多中间字符串,而且没有引用,另外因为字符串是存在字符串常量池,也就是在永久代中的, 所以GC不会来回收它们,这样就导致了一个严重的问题,内存占用过大

7. StringBuffer、StringBuilder类

为了解决上述的问题,就需要用到另外两个类StringBufferStringBuilder。这两个都是长度、内容可变的字符序列类型,字符串缓冲区类似于String,但是可以进行修改。它们两个方法上上很相似,主要区别是:StringBuffer是线程安全的,StringBuilder是线程不安全的,单个线程情况下,StringBuilder更快,线程的问题后续再介绍。

7.1 构造方法

java setcontenttype 纯文本 java set string_方法区_39

java setcontenttype 纯文本 java set string_String_40

两者是一样的,重点关注将String类直接转为相应的类的构造方法。

7.2 方法
最常用的就是append和insert方法,插入新数据:

java setcontenttype 纯文本 java set string_字符串_41

java setcontenttype 纯文本 java set string_java_42

有加入就有删除:

java setcontenttype 纯文本 java set string_java_43

还有设置:

java setcontenttype 纯文本 java set string_字符串_44

注意获取长度是capacity:

java setcontenttype 纯文本 java set string_赋值_45

还有一个需要特别记忆,翻转操作,String类没有:

java setcontenttype 纯文本 java set string_方法区_46

还有一个需要特别注意,它们的toString方法已经被重写,调用toString直接将这两类转为String返回:

java setcontenttype 纯文本 java set string_赋值_47

其他的方法很多String类的都有。

看一个简单例子:

package com.kaikeba.coreclasslibrary.string;

public class Demo2 {
    public static void main(String[] args) {
        //线程不安全的实现
        StringBuilder sb = new StringBuilder();
        //StringBuffer 线程安全的实现
        sb.append("1");
        sb.append("2");
        sb.append("3");
        String text = sb.toString();
        System.out.println(text);
    }
}


结果为:
123