API篇(JavaSE - 字符串(Char & String & StringBuilder & StringBuffer)(持续更新迭代)

目录

一、编码集

1. 前言

2. 什么是编码,数据类型和编码有什么关系?

3. 英文字符编码

ASCII编码

4. 中文编码

GB2312标准

GBK编码

其他中文编码

5. Unicode字符集

UTF-32

UTF-16

UTF-8

BOM

ANSI编码

二、字符类型(char)

1. 简介

2. 字符型数据与数值型数据之间的转换

3. 字符的比较和测试

4. Character类中的方法

5. 格式标识符

三、字符串类型

1. 不可变字符串(String)

1.1 概述

1.2 创建String

1. 两种方式

1.1  构造器创建字符串

1.2 直接使用“”定义

2. 两者创建区别

1.3 常用方法

1.4 常用API练习

1. 获取功能

2. 判断功能

3. 转换功能

4. 其他常用功能

1.5 练习题

1. 去除字符串两端的空格

2. 字符串中指定部分进行反转

3.  获取一个字符串在另一个字符串中出现的次数

4. 对字符串字符进行自然排序

5. 获取两个字符串中最大相同子串

2. 可变字符串(StringBuilder & StringBuffer)

2.1 概述

2.2 两种可变字符串

1. 线程不安全(StringBuilder)

1.1 构造器

1.2 常用方法

1.3 其他方法

2. 线程安全(StringBuffer)

四、字符串常用方法

1. 前言

2. 字符串的构造

1.1 使用常量进行直接赋值构造

1.2 使用new String对象

1.3 使用字符数组进行构造

3. 字符串的比较

==比较

equals方法比较

compareTo方法比较

compareToIgnoreCase(String str)方法

4. 字符串的查找

charAt(int index)方法

indexOf(String str)方法

5. 字符串类型与其它类型的相互转化

字符串转数字

字符串转数组

6. 字符串替换

7. 字符串拆分

8. 字符串截取

9. 大小写转换

10. 字符串去空格

String trim()

11. 字符串拼接

+号连接

join方法

12. 知识小结

五、演示示例

1. String

1.1. String类不可变的原理

1.2. String类创建字符串对象的2种方式

1.3. + 连接符

1.4. 使用String完成随机生成5位的验证码

1.5. 模拟用户登录

1.6. 手机号码屏蔽

1.7. 用户登录业务

1.8. 掌握String常用的其他API

2. StringBuilder(线程不安全)

2.1. StringBuilder操作字符串性能好的原因

2.2. 收任意整型数组,返回数组内容格式

3. StringBuffer(线程安全)

3.1. 字符串拼接

3.2. 字符串常见API(1)

3.3. 字符串常见API(2)

3.4. 追加字符串

3.5. 综合案例

3.6. 是否为回文字符串

3.7. 线程安全性

3.8. 性能

3.9. 总结

六、算法练习题

七、详细面试问题

1. 字符型常量和字符串常量的区别

2. String & StringBuffer & StringBuilder 的区别

2.1. 可变性

2.2. 线程安全性

2.3. 性能

2.4. 总结

八、简洁面试问题

1. 怎样比较字符串?用”==”还是用equals()?

2. 为什么对于安全性敏感的信息char[]要优于String?

3. 我们能不能在switch语句中使用String?

4. 怎样把字符串转换为整数?

5. 怎样分解一个有空白字符的字符串?

6. substring()方法真正做了什么?

7. String vs StringBuilder vs StringBuffer

8. 怎样重复一个字符串?

9. 怎样把字符串转换为日期?

10. 怎样统计一个字符在字符串中出现的次数?

11. Java String 值转化为boolean值

七、数据结构学习部门

一、编码集

1. 前言

我们在开发中是不是经常会遇到这样的问题,比如你在IDEA中创建了一个工程,里面有Java语言程序和中文注

释,有一天,根据工作需要,你要把其中的一部分Java源代码移植到Keil工程中,当你通过复制黏贴把相应文件移

植到Keil工程中,并使用MDK打开时,却发现,你移植的文件Java语言程序是正常显示的,但是中文却成了一堆

乱码,并且一编译各种莫名其妙的报错。

这其实就有可能是你的IDEA和Keil使用了不同的编码方式,因为大部分编码兼容ASCII编码,而Java语言程序是英

文字符,采用了ASCII编码,所以正常显示,而中文编码就不同了,比如内存中同样的0xB0A1,使用不同编码标

准去对0xB0A1解码,得到的可能就是不同的汉字。

2. 什么是编码,数据类型和编码有什么关系?

我们在计算机中经常见到的文字、数字、英文字母、图片、视频、音频等,这些信息在计算机中都是以二进制的

形式存储的,因为内存条是电子元器件组成的,它们只有高电平低电平两种状态,即0和1两个值。

实际上,我们所说的十进制、八进制等进制以及char、int、float等数据类型这些概念都是对于程序员而言的,比

如十进制、十六进制只是一个数字对我们的表现形式不同,逢十进一或逢十六进一的区别;而数据类型,int、

char、unsigned int等等,这些数据类型是对内存的解释不同,数据类型说明了这段内存所能表示的数据范围不

同,比如char占一个字节,表示的数据范围是0~255,int是4字节,unsigned int表示无符号4字节数据。

有时候在程序中我们会对变量进行类型转换,比如十进制转十六进制,又或者是char型转int型,这些转型都是对

内存的解释(主要是内存的大小,数据的范围),比如char b,那么b占一个字节,我们让b=1,然后转型

(int)b,其实b还是1,只不过它现在被解释为占据4个字节的内存。

总之,上面这些情况,不管如何转换,同一个数据不会因为类型转换而改变内存中的实际数据,b在char类型时是

00000001,转为int型后成了00000000000000000000000000000001,它还是那个1,不管是十六进制0x01还

是十进制1,它在内存中都是上面的二进制。

这是因为数据类型只是对内存的解释,而真正决定它们在计算机中的存储形式(是0001序列还是1110序列)的是

编码,编码是指一个数据在计算机中的01序列是如何存储的。

数据类型是固定大小内存块的别名,它说明了这块内存所能表示的数据大小范围;

字符集(character set)定义了文字和二进制的对应关系,并给每个文字分配一个一对一的唯一编号;

字符编码(character Encoding)规定了文字的编号是怎么在计算机中存储的。

3. 英文字符编码

ASCII编码

用8位二进制进行编码,用于表示控制字符、英文字符、数字字符。

因为使用8位二进制编码,所以ASCII编码只能表示256个字符,编号范围为0~255。

常用的ASCII码如下:

表示字符

十六进制形式

十进制形式

0~9

0x30~0x39

48~57

A~Z

0x41~0x5A

65~90

a~z

0x61~0x7A

97~122

不管是ASCII码的十六进制形式还是ASCII码的十进制形式,它都是一种解释性的概念,对内存数据的一种解释形

式,用于表达给程序员看的概念,它们在计算机中的存储都是同样的二进制数,不会因为进制改变而改变。这种

使用8位二进制来表示或存储字符的过程就叫做编码(一串二进制01和一个字符一一对应的过程)。这些用ASCII

码表示的字符的集合叫做ASCII字符集。

在英文世界中,使用26个字母就可以拼写出全部的英文单词,每个字字母就是一个字符,所以,用8位的ASCII码

就可以对整个英文世界进行编码。

简单来说:

ASCII(American Standard Code for Information Interchange)即美国信息交换标准编码

就是一套现代英语、数字、和其他西欧字符(不含中文)的编号规则

字符在计算机底层就是存储其编号的二进制形式

4. 中文编码

英文编码可以用字母编码来代替,这是因为所有英文单词都可以拆分成26个英文字母的组合。

而中文就不一样了,中文一个字就是一个整体,只能按照一个字来编码,中文汉字成千上万,如果仅用8位ASCII码来编码,那么是明显不

够的,ASCII码顶多表示256个汉字,所以就有了下面这些中文编码方式。

GB2312标准

GB2312总共覆盖了6763个常用汉字,GB2312标准把ASCII码表127号之后的扩展字符集去掉,并规定,小于127

(0x7F)的编码按照ASCII标准进行解码,当出现连续两个大于127(0x7F)的编码时,这两个连续的大于0x7F的

编码表示一个汉字,第一二个字节都是用0xA1~0xFE进行编码。

其中,ASCII码中原有的数字字符、英文字符、标点等称为半角字符,大于0x7F的相应字符编码称为全角字符。

GB2312解码规则:当使用GB2312编码标准时,给定一串字符编码,按照字节进行检测,首先检测每个字节的大

小,如果字节值小于0x7F,就用ASCII标准解码,如果连续两个字节的值都大于0x7F,就把这两个字节视为一个整

体,使用GB2312标准解码。

举例:

0x61

0xB0

0xA1

0x61

从第一个字节开始检测,0x61小于0x7F,用ASCII标准解码,它表示英文字符“a”,第二个字节0xB0大于

0x7F,第三个字节0xA1大于0x7F,连续两个字节大于0x7F,把它们连为一体使用GB2312解码为中文字

符“啊”,第四个字节0x61小于0x7F,用ASCII标准解码,它表示英文字符“a”。

综上,可解码如下:

0x61

0xB0

0xA1

0x61

a

a

a

GBK编码

GBK编码在GB2312的基础上又增加了14240个汉字、生僻字和符号。

按照GB2312的编码方式,两个字节已经不够用了,这时,GBK编码制定了新的标准:只要出现一个大于0x7F的字

节,那么这个字节和它后面一个字节共两个字节就表示一个汉字(GB2312规定两个字节都大于0x7F才表示一个汉

字),这样做的好处就是,GBK编码兼容了ASCII编码和GB2312编码。

GBK解码规则:当使用GB2312编码标准时,给定一串字符编码,按照字节进行检测,首先检测每个字节的大小,

如果字节值小于0x7F,就用ASCII标准解码,如果遇到一个大于0x7F的字节,就把该字节和它后面一个字节连在一

起用GBK标准进行解码,然后从第三个字节开始继续遍历检测。

举例:

0x61

0xB0

0x56

0x62

从第一个字节开始检测,0x61小于0x7F,用ASCII标准解码,它表示英文字符“a”,第二个字节0xB0大于

0x7F,那么就把0xB0、0x56连在一起用GBK标准解码,然后从0x62开始继续检测,解码后如下:

0x61

0xB0

0x56

0x62

a

癡(chi)

癡(chi)

其他中文编码

GB18030编码:使用4字节编码,兼容ASCII、GB2312、GBK。包括2000年编制的GB18030-2000,2005年编

制的GB18030-2005。

Big5编码:多用于台湾香港等地,主要是收录了繁体字。在包含汉字数量上来说,Big5是GBK的子集,但是二者

的编码方式是不同的,比如同样“啊”,GBK编码为0xB0A1,Big5编码为0xB0DA。

5. Unicode字符集

每个国家和地区都有一套自己的文字,不同的文字系统就要使用不同的编码标准,这就出现这样一个问题,同一

个二进制编码在不同的编码标准中可能代表了不同的字符,比如0xB0A1,在GBK编码标准中为“啊”,而在Big5

编码标准中就不是这个字了。这样,各个编码标准之间的不兼容就导致使用起来非常不方便。

国际标准化组织ISO,将全球所有的语言所使用的字母、符号、文字进行统一编号,每个字符指定唯一一个标号与

之对应(ASCII码编号不变),字符的编号从0x000000~0x10FFFF,该编号集称为Universal Multiple-Octet

coded Character Set,简称UCS,一般也叫做Unicode。

Unicode字符集仅仅是对所有字符进行了编号,并没有指定这些编号的编码规则,所以,后来才出现了各种

Unicode的编码规则UnicodeTransformation Format,典型的Unicode编码规则如UTF-8,UTF-16,UTF-32

等。

UTF-32

Unicode Transformation Format 32,用32位(4字节)对Unicode字符集进行编码。编码时,Unicode字符集

中的每一个字符都用4字节表示,直接把字符对应的Unicode编号转换为二进制数进行存储。

而正因为UTF-32用4字节为每个字符编码,所以,UTF-32不兼容ASCII编码,使用ASCII编码标准写的程序,通过

UTF-32编码方式打开会显示乱码。解码时,直接按四个字节检测,编码与Unicode标号一一对应。

字符:A

ASCII编码:0x41

Unicode编号:0x0000 0041

UTF-32编码:0x0000 0041

字符:啊

GBK编码:0xB0A1

Unicode编号:0x0000 554A

UTF-32编码:0x0000 554A

UTF-16

Unicode Transformation Format 16,用16位(2字节)或32位(4字节)对Unicode字符集进行编码。

对Unicode字符编号在065535的字符使用2字节编码,将每个字符的编号直接转换为2字节的二进制数0x00000xFFFF。

而Unicode字符集在0xD800~0xDBFF区间内的编号不表示任何字符,UTF-16用这段编号与Unicode字符集中大

于0xFFFF的字符编号进行映射,得到扩展的4字节编码。UTF-16也不兼容ASCII编码。

UTF-16解码时,按两个字节去检测,如果这两个字节都不在0xD800~0xDFFF之间,就说明是双字节编码的字

符,使用双字节解码;如果这两个字节在0xD800~0xDFFF之间,说明是4字节编码的字符,以4字节解码。

UTF-8

Unicode Transformation Format 8,用1,2,3,4个字节对Unicode字符集进行编码,每个字符根据自己的编

号范围进行相应编码。

它的编码规则是这样的:

对于UTF-8单字节的编码,该字节最高位设为0,剩余位填入字符的Unicode编号,

对于Unicode编号在0x00000000~0x0000007F的字符,UTF-8编码只要一个字节,兼容ASCII编码。

对于N字节的编码,第一字节最高位开始,前N位置为1,第N+1位设0,剩余字节最高位设为10,

这N个字节的其余空位填充该字符的Unicode编号,高位补0。

具体可见下表:

解码时,看第一个字节

0开头:单字节解码;

110开头:双字节解码;

1110开头:三字节解码;

11110开头:四字节解码;

UTF-8编码的时候,汉字一般是占三个字节的。

BOM

Byte Order Mark,我们在Notepad++中的Encoding选项中可以看到诸如Encoding in UTF-8,以及Encoding

in UTF-8-BOM这样的选项,带不带标签不会影响对字符的编码解码,假如把不带标签的UTF-8编码转换为带标签

的UTF-8-BOM编码,程序和中文注释都不会出现乱码,但是这两种是有区别的。

比如我们常用的emWin,在emWin中文支持中,它只支持不带标签的UTF-8编码,如果使用带标签的UTF-8-

BOM,虽然不会报错,但是在控件中,无法显示这些中文。

ANSI编码

ANSI编码是Windows中的一种称呼,像GBK、GB2312都是ANSI编码,在不同语言的操作系统中,ANSI表示的

编码是不同的,比如中文、泰文、法文都有各自的编码方式,这些编码方式对ASCII编码的扩展就是ANSI。

二、字符类型(char)

1. 简介

字符型char在Java语言中占用 2 个字节,char类型的字面量必须使用半角的单引号括起来,取值范围为[ 0 -

65535 ],char 和 short 都占用 2 个字节,但是 char 可以取到更大的正整数,因为 char 类型没有负数。

Java语言中的char类型变量可以容纳一个汉字。

请看以下程序:

public class CharTest01 {
    public static void main(String[] args) {
        char c = '中';
        System.out.println(c);
    }
}

我们对以上的程序编译并运行,请看下图结果:

我们可以看到 Java 中的 char 类型确实可以储存一个汉字。

我们再来看以下程序,假设字符我们采用双引号括起来会怎么样:

public class CharTest01 {
    public static void main(String[] args) {
        char c = "中";
        System.out.println(c);
    }
}

我们对以上的程序进行编译,请看下图编译结果:


我们看到编译器报错了,并且提示的错误信息是 “不兼容的类型” ,这是因为双引号括起来的不是 char 类型,

而是 String 类型,其实 String 类型就是 Java 中的字符串类型,但大家要知道字符串不属于基本数据类型,而是

引用数据类型,所以类型不兼容。

接下来我们来测试一下两个或多个字符是否可以使用单引号括起来,请看以下代码:

public class CharTest01 {
    public static void main(String[] args) {
        char c = 'ab';
        System.out.println(c);
    }
}

我们对以上的程序进行编译,请看下图编译结果:

我们可以看出,编译器报错了,错误信息是“未结束的字符文字”,这是因为 Java 中有规定,字符型只能是单个

字符,当编译器检测到' ab ' 的时候,左边以单引号开始,继续检测到 a 字符,然后编译器会继续检查下一个字符

是否为另一半单引号,结果不是,而是 b,所以编译器报错了。这也说明了 Java 中的字符只能是单个字符,不能

是多个字符。

接下来,我们再来看一看关于转义字符,转义字符指用一些普通的字符组合代表一些特殊的字符,由于组合用的

字符改变了原意,称为转义字符。

Java 中的转义字符以 \ 开始,常见的转义字符有:\t、\n、\u、\、',",其中\t代表制表符,\n 是换行符,\表示

一个普通的\字符,表示一个普通的',"表示一个普通的"。

请看以下代码:

public class CharTest02 {
    public static void main(String[] args) {
        char c1 = 't';
        System.out.println("这是一个普通的字符 = " + c1);
        char c2 = '\t';
        System.out.println("abc" + c2 + "def");
    }
}

我们对以上的程序进行编译并运行,请看下图结果:

对于以上程序,表面看起来 ' \t ' 是由两个字符构成,按说应该编译报错,因为它毕竟是两个字组成的字符串,可

是最终的结果编译通过了,并且正常运行了,这说明了 ' \t ' 表示 1 个字符,所以 \ 具有转义功能,根据以上输出

结果可以看出 \t 是制表符(abc 和 def 之间的空白就是制表符)。

接下来我们来看一看其它的转义字符。

请看以下程序:

public class CharTest03 {
    public static void main(String[] args) {
        System.out.println("hello\nworld");
        System.out.println('\'');
        System.out.println('\\');
        System.out.println("\"");
        System.out.println('\u4e2d');
    }
}

我们对以上的程序进行编译并运行,请看下图运行结果:


通过以上代码的测试,hello 和 world 之间换行了,所以 \n 代表一个换行符。

其余参考如下

2. 字符型数据与数值型数据之间的转换

char型数据可以转换成任意一种数值类型,反之亦然。

将整数转换成char型数据时,只用到该数据的低十六位,其余部分都被忽略。

例如:十六进制整数转换字符型、八进制整数转换字符型、十进制转换字符型等

3. 字符的比较和测试

  • 'a'< 'b'为true,因为'a '(97)的 Unicode值比'b'(98)的 Unicode值小。
  • 'a' < 'A'为false,因为 'a'(97)的 Unicode值比'A'(65)的 Unicode值大。
  • 'I'< '8'为true,因为‘I’(49)的 Unicode值比'8'(56)的 Unicode值小。

下列代码测试字符ch是大写字母、小写字母,还是数字字符。

if (ch >= 'A’&&ch <= 'Z')
    System.out.println(ch + " is an uppercase letter");
else if (ch >= 'a'&&ch <= 'z')
    System.Out.println(ch + " is a lowercase letter");
else if(ch>=‘a’&ch<=‘z’)
    System.out.print1n(ch + " is a numeric character");

4. Character类中的方法

5. 格式标识符

格式标识符指定每个条目应该如何显示。这里的条目可以是数值、字符、布尔值或字符串。

简单的格式标识符是以百分号(%)开头的转换码。

常用的格式标识符:

条目与标识符必须在次序、数量和类型上匹配。

例如:count的格式标识符应该是%d,而amount的格式标识符应该是默认情况下,浮点值显示小数点后6位数字。

可以在标识符中指定宽度和精度

比如:

显示:

1234#Java¥51.67

三、字符串类型

1. 不可变字符串(String)

1.1 概述

我们知道char类型只能表示一个字符,为了表示一串字符,使用java.lang.String类代表字符串,

  • 从源码可以看到java.lang.String 是被final修饰的,所以,字符串对象一旦创建就不可变。
    底层实际上是一个用final修饰的字符数组进行描述
  • 字符串对象具有只读特性,任何对字符串的操作实际上是对其引用的操作。
  • 任何看起来像是修改String对象的操作其本质上都是创建了一个新的字符串对象,而最初的字符串对象并没有发生改变
  • 因为字符串是一个引用数据类型,所以字符串的比较必须使用equals方法,而String类也已经重写了equals和toString方法。

以“”方式给出的字符串对象,在堆内存中的字符串常量池中存储

因为字符串在程序设计中是不可变的,但同时又会频繁地使用,所以Java虚拟机为了提高效率并节约内存,

对具有相同字符序列的字符串直接量使用同一个实例,无非就是放在字符串常量池中!

使用String类拼接字符串时应该注意:

  • 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
  • 只要其中有一个是变量,结果就在堆中
  • 如果拼接的结果调用  intern()  方法,返回值就在常量池中

1.2 创建String

1. 两种方式
1.1  构造器创建字符串

方法声明

功能描述

String()

创建一个内容为空的字符串

String(String value)

根据指定的字符串内容创建对象

String(char[] value)

根据指定的字符数组创建对象

String(byte[] bytes)

根据指定的字节数组创建对象

由于String类比较常用,也可以直接定义字符串常量:String str="abc";

1.2 直接使用“”定义
2. 两者创建区别

以“”方式给出的字符串对象,在字符串常量池中存储,而且相同内容只会在内存中存储一份,

通过构造器new对象,每new一次都会产生一个新对象存放在堆内存中

1.3 常用方法

方法声明

功能描述

int indexOf(int ch)

返回指定字符ch在字符串中第一次出现位置的索引

int lastIndexOf(int ch)

返回指定字符ch在字符串中最后一次出现位置的索引

int indexOf(String str)

返回指定子字符串str在字符串第一次出现位置的索引

int lastIndexOf(String str)

返回指定子字符串str在此字符串中最后一次出现位置的索引

char charAt(int index)

返回字符串中index位置上的字符,其中index的取值范围是0~(字符串长度-1)

Boolean endsWith(String suffix)

判断此字符串是否以指定的字符串结尾

int length()

返回此字符串的长度

boolean equals(Object anObject)

将此字符串与指定的字符串比较

boolean isEmpty()

判断字符串长度是否为0,如果为0则返回true,反之则返回flase

boolean startsWith(String prefix)

判断此字符串是否以指定的字符串开始

boolean contains(CharSequence cs)

判断此字符串中是否包含指定的字符序列

String toLowerCase()

使用默认语言环境的规则将String中的所有字符都转换为小写

String toUpperCase()

使用默认语言环境的规则将String中的所有字符都转换为大写

static String valueOf(int i)

将int变量i转换成字符串

char[] toCharArray()

将此字符串转换为一个字符数组

String replace(CharSequence oldstr, CharSequence newstr)

返回一个新的字符串,它是通过用 newstr替换此字符串中出现的所有 oldstr得到的

String[] split(String regex)

根据参数regex将原来的字符串分割为若干个子字符串

String substring(int beginIndex)

返回一个新字符串,它包含从指定的beginIndex处开始,直到此字符串末尾的所有字符

String substring(int beginIndex, int endIndex)

返回一个新字符串,它包含从指定的beginIndex处开始,直到索引endIndex-1处的所有字符

String trim()

返回一个新字符串,它去除了原字符串首尾的空格

1.4 常用API练习

1. 获取功能

length()方法 获取字符串长度

String str = "abcdef";
System.out.println(str.length());//输出结果:6

charAt(int index)方法 传递一个下标参数,返回字符串对应位置的字符

String str = "abc";
System.out.println(str.charAt(1));//输出结果:b

indexOf()方法 传递某个字符,返回在字符串中的第一个位置

String str = "abcabc";
System.out.println(str.indexOf('a'));//输出结果:0

subString(int start) 默认是取到字符串末尾

String str = "abcdef";
System.out.println(str.subString(2));//输出结果:cdef

subString(int start,int end) 注:范围左闭右开,不包含下标为end的那位

String str = "abcdefgh";
System.out.println(str.subString(2,5));//输出结果:cde
2. 判断功能

equals() 判断字符串内容是否相同,区分大小写。

String str1 = "abc";
String str2 = "ABC";
System.out.println(str1.equals(str2));//输出结果:false

contains() 判断该字符串是否包含传递过来的字符串。

String str1 = "我是猪";
String str2 = "我是";
String str3 = "是猪";
System.out.println(str1.contains(str2));//输出结果:true
System.out.println(str1.contains(str3));//输出结果:true

startsWith() 判断字符串是否以传进来的字符串开头。

endsWith() 判断字符串是否以传进来的字符串结尾。

String str1 = " 我是猪";
String str2 = " ";
System.out.println(str1.startsWith(str2));//true
System.out.printl(str1.endsWith(str2));//false

isEmpty() 判断字符串是否为空。

String str = "";
String str1 = "a";
System.out.println(str.isEmpty());//true
System.out.println(str1.isEmpty());//false
3. 转换功能

getBytes() 返回值类型 byte[]

使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。

toCharArray() 将String类型的字符串转化为char字符数组

Strint str = "我是你爹";
char[] c = str.toCharArray();
System.out.println(c[0]);//输出结果:我
System.out.println(c[1]);//输出结果:是
System.out.println(c[2]);//输出结果:你
System.out.println(c[3]);//输出结果:爹

valueOf(char[] data) 将传递的字符数组,组合成字符串。

char[] c = {'a','b','c','d'};
String str = new String();
str = str.valueOf(c);
System.out.println(str);//输出结果:abcd

toLowerCase() 把字符串转成小写 toUpperCase() 把字符串转成大写

comcat() 字符串拼接

String str1 = "abc";
String str2 = "def";
String str3 = str1.concat(str2);
System.out.println(str3);//输出结果:abcdef
4. 其他常用功能

replace() 用传递的字符或字符串,替代指定的字符或者字符串。

trim() 去除两端空格

String str = "  哈哈哈  ";
System.out.println(str);//输出结果:  哈哈哈  ;
str = str.trim();
System.out.println(str);//输出结果:哈哈哈;

compareTo()

//源码:
public int compareTo(String anotherString) {
        int len1 = value.length;
        int len2 = anotherString.value.length;
        int lim = Math.min(len1, len2);
        char v1[] = value;
        char v2[] = anotherString.value;
 
        int k = 0;
        while (k < lim) {
            char c1 = v1[k];
            char c2 = v2[k];
            if (c1 != c2) {
                return c1 - c2;
            }
            k++;
        }
        return len1 - len2;
}

解析:如果字符串与传递字符串的长度不等,那么返回就是两个字符串的长度差值;

如果两个字符串长度相等,那么返回的就是,两个字符串长度最小值位置的字符ASCII码的差值。

String str1 = "abc";
String str2 = "ab";
String str3 = "abd";
String str4 = "abcdef";
int a = str1.compareTo(str2);
System.out.println(a);//输出结果:1
int b = str1.compareTo(str3);
System.out.println(b);//输出结果:-1
int c = str1.compareTo(str4);
System.out.println(c);//输出结果:-3

1.5 练习题

1. 去除字符串两端的空格

模拟一个trim方法,去除字符串两端的空格

	@Test
    /**
     * 模拟一个trim方法,去除字符串两端的空格
     */
    public void test1(){
        String s=" 1 23 ";
        String s1=s.replaceFirst(" ","");
        char[] chars=s1.toCharArray();
        char[] chars1=new char[chars.length-1];
        for(int i=0;i<chars.length-1;i++){
            chars1[i]=chars[i];
        }
        String s2=new String(chars1);
        System.out.println(s);
        System.out.println(s2);
    }

运行结果为:

1 23 
1 23
2. 字符串中指定部分进行反转

将一个字符串进行反转。将字符串中指定部分进行反转。比如  “ab  cdef  g”  反 x转为  ”ab  fedc  g”

	@Test
    /**
     * 将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdefg”反
     * 转为”abfedcg”
     */
    public void test2(){
        String str="abcdefg";
        String substr="bcd";
        int index=str.indexOf(substr);
        char[] chars=str.toCharArray();
        for(int i=index,k=0;i<(index+substr.length())/2;i++,k++){
           char ch=chars[i];
           chars[i]=chars[index+substr.length()-1-k];
           chars[index+substr.length()-1-k]=ch;
        }
        String str1=new String(chars);
        System.out.println(str);
        System.out.println(substr);
        System.out.println(str1);
    }

运行结果为:

abcdefg
bcd
adcbefg
3.  获取一个字符串在另一个字符串中出现的次数
	@Test
    /**
     * 获取一个字符串在另一个字符串中出现的次数
     */
    public void test3(){
        String str="uibufangqijuiayubufw";
        String substr="buf";
        int count=0;
        int index=0;
        while(str.indexOf(substr,index)>=0){
            count++;
            index=str.indexOf(substr,index)+1;
        }
        System.out.println(count);
    }

运行结果:

2
4. 对字符串字符进行自然排序
	@Test
    /**
     * 对字符串中字符进行自然顺序排序
     */
    public void test5(){
        String s="908762";
        char[] chars=s.toCharArray();
        for(int i=0;i<chars.length;i++){
            for(int j=0;j<chars.length-i-1;j++){
                if(chars[j+1]<chars[j]){
                    char temp=chars[j+1];
                    chars[j+1]=chars[j];
                    chars[j]=temp;
                }
            }
        }
        String s1=new String(chars);
        System.out.println(s1);
 
    }

运行结果:

026789
5. 获取两个字符串中最大相同子串

获取两个字符串中最大相同子串。

比如:

 str1 = "abcwerthelloyuiodef“;str2 = "cvhellobnm"
    @Test
    /**
     * 获取两个字符串中最大相同子串。比如:
     * str1 = "abcwerthelloyuiodef“;str2 = "cvhellobnm"
     */
    public void test6(){
        String str1="abcwerthellobyuiodef";
        String str2="cvhellobnm";
        String str;
        String  max=str1.length()>=str2.length()?str1:str2;
        String  min=str1.length()<str2.length()?str1:str2;
        for (int i = 0; i <min.length(); i++) {
            for(int x=0,y=min.length()-i;y<min.length();y++,x++){
                str=str2.substring(x,y);
                if(max.indexOf(str)>0){
                    System.out.println(str);
                    return;
                }
            }
 
        }
    }

运行结果:

hellob

2. 可变字符串(StringBuilder & StringBuffer)

2.1 概述

可变字符串java.lang.StringBuilder和java.lang.StringBuffer,有些时候,我们需要较短的字符串构建字符串,例

如,按键或来自文件中的单词。采用不可变字符串java.lang.String连接的方式达到目的效率比较低。

因为每次连接字符串,都会构建一个新的 String 对象,既耗时,又浪费空间,所以,我们就需要使用可变字符串

java.lang.StringBuilder和java.lang.StringBuffer来实现,这里用StringBuilder为例,StringBuilder是线程不安

全的,它的前身是StringBuffer,StringBuffer效率稍有些低,因为它是线程安全的,它能够帮助我们在多线程情

况下执行或删除字符的操作,而不会出现线程安全问题,但是在单线程情况下,并不会出现线程竞争问题,所

以,在单线程的情况下,使用StringBuilder的效率要高一些,所以,这里都以StringBuilderAPI为例,

StringBufferAPI类似!

注意:如果只有一个任务被允许执行方法之外,StringBuilder类与StringBuffer类是很相似的。

如果是多任务并发访问,就使用StringBuffer,因为这种情况下需要同步以防止StringBuffer崩溃。

2.2 两种可变字符串

1. 线程不安全(StringBuilder)
1.1 构造器

在字符串构建器的末尾追加新内容,在字符串构建器的特定位置插人新的内容,还可以删除或替换字符串构建器

中的字符。

1.2 常用方法
  1. append(String str)/append(Char c):字符串连接
System.out.println("StringBuilder:"+strB.append("ch").append("111").append('c'));
//return "StringBuilder:ch111c"

2, toString():返回一个与构建起或缓冲器内容相同的字符串

System.out.println("String:"+strB.toString());
//return "String:ch111c"

3, appendcodePoint(int cp):追加一个代码点,并将其转换为一个或两个代码单元并返回this

System.out.println("StringBuilder.appendCodePoint:"+strB.appendCodePoint(2));
//return "StringBuilder.appendCodePoint:ch111c"

4, setCharAt(int i, char c):将第 i 个代码单元设置为 c(可以理解为替换)char字符使用 ‘  ’

strB.setCharAt(2, 'd');
System.out.println("StringBuilder.setCharAt:" + strB);
//return "StringBuilder.setCharAt:chd11c"

5, insert(int offset, String str)/insert(int offset, Char c):在指定位置之前插入字符(串)

System.out.println("StringBuilder.insertString:"+ strB.insert(2, "LS"));
//return "StringBuilder.insertString:chLSd11c"
System.out.println("StringBuilder.insertChar:"+ strB.insert(2, 'L'));
//return "StringBuilder.insertChar:chLLSd11c"

6, delete(int startIndex,int endIndex):删除起始位置(含)到结尾位置(不含)之间的字符串

System.out.println("StringBuilder.delete:"+ strB.delete(2, 4));
//return "StringBuilder.delete:chSd11c"
1.3 其他方法

StringBuilder类还提供了许多其他处理字符串构建器和获取它的属性的方法

2. 线程安全(StringBuffer)

用法与StringBuilder类似,只不过是线程安全的

四、字符串常用方法

1. 前言

现在我们已经知道,java中没有内置的字符串类型,而是标准Java类库中提供了一个预定义类,所以字符串也叫做

String,每个String类都是由双引号(“”)引起来的,String在java中也是非常重要的,下面让我们一起复习一下

String类的10个常用方法。

2. 字符串的构造

1.1 使用常量进行直接赋值构造

String str="hello java";

1.2 使用new String对象

String str1=new String("hello");
1

1.3 使用字符数组进行构造

  char[] arr={'j','a','v','a'};
  String str2=new String(arr);

注意:需要注意的是String是引用类型,内部存储的并不是字符串本身。

3. 字符串的比较

==比较

在String中==比较的是引用的字符串对象是否为同一个

        String str3="999";
        String str4="999";
        String str5=new String("999");
        System.out.println(str3==str4);
        //打印true
        System.out.println(str3==str5);
        //打印false

equals方法比较

equals方法接收类型为Object类型,返回类型为布尔类型,比较的是两个对象中的内容是否相同

 String str3="999";
 tring str5=new String("999");
 System.out.println(str3.equals(str5));
 //打印true

compareTo方法比较

compareTo方法接收类型为String类型,返回值为int类型。

比较方法为:

  1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值。
  2. 如果前k个字符都相等,只是长度不同,那么返回两个字符串长度差值。
        String str6="hello";
        String str7="help";
        String str8="help me";
        System.out.println(str6.compareTo(str7));
        //打印-4,l与p的字符大小差值
        System.out.println(str7.compareTo(str8));
        //打印-3,长度差值

compareToIgnoreCase(String str)方法

次方法与compareTo方法比较形式大致相同,只是不区分字符串大小写。

4. 字符串的查找

charAt(int index)方法

此方法返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常

       String str9="sleep";
       System.out.println(str9.charAt(2));
       //打印e

indexOf(String str)方法

此方法为返回str第一次出现的位置,没有返回-1。

        String str10="hello java";
        System.out.println(str10.indexOf("lo"));
        //打印3

5. 字符串类型与其它类型的相互转化

字符串转数字

不同基本类型对应不同包装类,方法名后缀不相同。

        String str11="1314520";
        int a=Integer.parseInt(str11);
        System.out.println(a);
        //打印数字1314520

字符串转数组

使用toCharArray方法转为数组

        String str12="name";
        char[] arr1=str12.toCharArray();
        for (char c :arr1) {
            System.out.print(c);
        }
        //打印name

6. 字符串替换

接收类型与返回类型皆为String类型

replaceAll与replaceFirst分别为替换所有指定内容与替换首指定内容

        String str13="hello";
        System.out.println(str13.replaceAll("lo", "p"));
        //打印help
        System.out.println(str13.replaceFirst("l", "e"));
        //打印heelo

7. 字符串拆分

将字符串以指定的格式全部拆分

将字符串以指定的格式,拆分为limit组

        String str14="123456789";
        String[] arr2=str14.split("");
        String[] arr3=str14.split("",4);
        System.out.println(arr2.length);
        //打印9
        System.out.println(arr3.length);
        //打印4

8. 字符串截取

String substring(开始截取的下标, 开始不截取的下标)

        String str15="java";
        System.out.println(str15.substring(1, 3));
        //打印av

9. 大小写转换

将字符串全部变为小写

将字符串全部变为大写

        String str16="AbC";
        System.out.println(str16.toLowerCase());
        //打印abc
        String str17="aBc";
        System.out.println(str17.toUpperCase());
        //打印ABC

10. 字符串去空格

String trim()

作用:去掉字符串中的左右空格,保留中间空格

        String str18="  o o  ";
        System.out.println(str18);
        //打印  o  o
        System.out.println(str18.trim());
        //打印o  o

11. 字符串拼接

+号连接

        String str19="hel";
        String str20="lo";
        System.out.println(str19+str20);
        //打印hello

join方法

第一个参数为分隔符,后面参数为需要放在一起的元素。

        String str21=String.join("","j","a","v","a");
        System.out.println(str21);
        //打印java

12. 知识小结

以上就是今天要讲的内容,本文仅仅简单复习了一些以字符串为操作对象的方法的使用,而String中提供了大量能

使我们快速便捷地处理字符串的方法,这些需要我们一个一个的敲一敲。

五、演示示例

1. String

1.1. String类不可变的原理

package com.zheng.d3_string;

/**
     目标:了解String类的特点:String类不可变的原理。
 */
public class StringDemo1 {
    public static void main(String[] args) {
        String name = "政哥";
        name += "教育"; // name = name + "教育"
        name += "中心";
        System.out.println(name);
    }
}

1.2. String类创建字符串对象的2种方式

package com.zheng.d3_string;

/**
    目标:String类创建字符串对象的2种方式
 */
public class StringDemo2 {
    public static void main(String[] args) {
        // 方式一:直接使用双引号得到字符串对象
        String name = "我爱你中国";
        System.out.println(name);

        // 方式二:
        // 1、public String(): 创建一个空白字符串对象,不含有任何内容 (几乎不用)
        String s1 = new String(); // s1 = ""
        System.out.println(s1);

        // 2、public String(String): 根据传入的字符串内容,来创建字符串对象(几乎不用)
        String s2 = new String("我是中国人");
        System.out.println(s2);

        // 3、public String(char[] c): 根据字符数组的内容,来创建字符串对象
        char[] chars = {'a' , 'b' , '中', '国'};
        String s3 = new String(chars);
        System.out.println(s3);

        // 4、public String(byte[] b):  根据字节数组的内容,来创建字符串对象
        byte[] bytes = {97, 98, 99, 65, 66, 67};
        String s4 = new String(bytes);
        System.out.println(s4);

        System.out.println("---------------------------------------");
        String ss1 = "abc";
        String ss2 = "abc";
        System.out.println(ss1 == ss2);

        char[] chars1 = {'a' , 'b' , 'c'};
        String ss3 = new String(chars1);
        String ss4 = new String(chars1);
        System.out.println(ss3 == ss4);
    }
}

1.3. + 连接符

package com.zheng.d3_string;

public class StringDemo3 {
    public static void main(String[] args) {
        String s1 = "abc";
        String s2 = "a" + "b" + "c";
        System.out.println(s1 == s2);
    }
}

1.4. 使用String完成随机生成5位的验证码

package com.zheng.d3_string;

import java.util.Random;

/**
    练习题:使用String完成随机生成5位的验证码。
 */
public class StringExec6 {
    public static void main(String[] args) {
        // 1、定义可能出现的字符信息
        String datas = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        
        // 2、循环5次,每次生成一个随机的索引,提取对应的字符连接起来即可
        String code = "";
        Random r = new Random();
        for (int i = 0; i < 5; i++) {
            // 随机一个索引
            int index = r.nextInt(datas.length());
            char c = datas.charAt(index);
            code += c;
        }

        // 3、输出字符串变量即可
        System.out.println(code);
    }
}

1.5. 模拟用户登录

package com.zheng.d3_string;

import java.util.Scanner;

/**
    练习题:模拟用户登录
 */
public class StringExec7 {
    public static void main(String[] args) {
        // 1、定义正确的登录名称和密码
        String okLoginName = "admin";
        String okPassword = "政哥";

        // 2、定义一个循环,循环3次,让用户登录
        Scanner sc = new Scanner(System.in);
        for (int i = 1; i <= 3; i++) {
            System.out.println("请您输入登录名称:");
            String loginName = sc.next();
            System.out.println("请您输入登录密码:");
            String password = sc.next();

            // 3、判断登录是否成功!
            if(okLoginName.equals(loginName)){
                // 4、判断密码是否正确
                if(okPassword.equals(password)){
                    System.out.println("登录成功!欢迎进入系统随意浏览~~~~");
                    break;
                }else {
                    // 密码错误了
                    System.out.println("您的密码不正确!您还剩余" + (3 - i) +"次机会登录!");
                }
            }else {
                System.out.println("您的登录名称不正确!您还剩余" + (3 - i) +"次机会登录!");
            }

        }

    }

}

1.6. 手机号码屏蔽

package com.zheng.d3_string;

import java.util.Scanner;

/**
    练习题:手机号码屏蔽
 */
public class StringExec8 {
    public static void main(String[] args) {
        // 1、键盘录入一个手机号码
        Scanner sc = new Scanner(System.in);
        System.out.println("请您输入您的手机号码:");
        String tel = sc.next();

        // 2、截取号码的前三位,后四位    18665666520
        String before = tel.substring(0, 3); // 0  1  2
        String after = tel.substring(7);  // 从索引7开始截取到手机号码的末尾

        String s = before + "****" + after;
        System.out.println(s);
    }
}

1.7. 用户登录业务

package com.zheng.d3_string;

import java.util.Scanner;

public class StringAPIEqualsDemo4 {
    public static void main(String[] args) {
        // 1、正确登录名和密码
        String okName = "yjxz";
        String okPassword = "123456";

        // 2、请您输入登录名称和密码
        Scanner sc = new Scanner(System.in);
        System.out.println("登录名称:");
        String name = sc.next();
        System.out.println("登录密码:");
        String password = sc.next();

        // 3、判断用户输入的登录名称和密码与正确的内容是否相等。
        if(okName.equals(name ) && okPassword.equals(password)){
            System.out.println("登录成功!");
        }else {
            System.out.println("用户名或者密码错误了!");
        }

        // 4、忽略大小写比较内容的Api: 一般用于比较验证码这样的业务逻辑
        String sysCode = "23AdFh";
        String code1 = "23aDfH";
        System.out.println(sysCode.equals(code1)); // false
        System.out.println(sysCode.equalsIgnoreCase(code1)); // true
    }
}

1.8. 掌握String常用的其他API

package com.zheng.d3_string;

/**
    目标:掌握String常用的其他API。
 */
public class StringAPIOtherDemo5 {
    public static void main(String[] args) {
        // 1、public int length(): 获取字符串的长度
        String name = "我爱你中国love";
        System.out.println(name.length());

        // 2、public char charAt(int index): 获取某个索引位置处的字符
        char c = name.charAt(1);
        System.out.println(c);

        System.out.println("------------遍历字符串中的每个字符--------------");
        for (int i = 0; i < name.length(); i++) {
            char ch = name.charAt(i);
            System.out.println(ch);
        }
        // 3、public char[] toCharArray():: 把字符串转换成字符数组
        char[] chars = name.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            char ch = chars[i];
            System.out.println(ch);
        }

        // 4、public String substring(int beginIndex, int endIndex) :截取内容,(包前不包后的)
        String name2 = "Java是最厉害的编程语言!";
        //              01234567   89
        String rs = name2.substring(0, 9);
        System.out.println(rs);
        String rs1 = name2.substring(4, 9);
        System.out.println(rs1);

        // 5、public String substring(int beginIndex):从当前索引一直截取到末尾
        String rs2 = name2.substring(4);
        System.out.println(rs2);

        // 6、public String replace(CharSequence target, CharSequence replacement)
        String name3 = "政哥是最厉害的00后,政哥棒棒的!我好爱政哥";
        String rs3 = name3.replace("政哥", "***");
        System.out.println(rs3);

        // 7、public boolean contains(CharSequence s)
        System.out.println(name3.contains("政哥")); // true
        System.out.println(name3.contains("政哥")); // false

        // 8、public boolean startsWith(String prefix)
        System.out.println(name3.startsWith("政哥"));
        System.out.println(name3.startsWith("政哥是最厉害的"));
        System.out.println(name3.startsWith("政哥是最厉害的2"));

        // 9、public String[] split(String s): 按照某个内容把字符串分割成字符串数组返回。
        String name4 = "王宝强,贾乃亮,陈羽凡";
        String[] names = name4.split(",");
        for (int i = 0; i < names.length; i++) {
            System.out.println("选择了:" + names[i]);
        }
    }
}

2. StringBuilder(线程不安全)

2.1. StringBuilder操作字符串性能好的原因

package com.zheng.d3_string.stringbuilder;

/**
    目标:学会使用StringBuilder操作字符串,最终还需要知道它性能好的原因
 */
public class StringBuilderDemo1 {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder(); // ""
        sb.append("a");
        sb.append("b");
        sb.append("c");
        sb.append(1);
        sb.append(false);
        sb.append(3.3);
        sb.append("abc");
        System.out.println(sb);

        StringBuilder sb1 = new StringBuilder();
        // 支持链式编程
        sb1.append("a").append("b").append("c").append("我爱你中国");
        System.out.println(sb1);

        // 反转
        sb1.reverse().append("110");
        System.out.println(sb1);

        System.out.println(sb1.length());

        // 注意:StringBuilder只是拼接字符串的手段:效率好。
        // 最终的目的还是要恢复成String类型。
        StringBuilder sb2 = new StringBuilder();
        sb2.append("123").append("456");
        // 恢复成String类型
        String rs = sb2.toString();
        check(rs);
    }

    public static void check(String data){
        System.out.println(data);
    }
}

2.2. 收任意整型数组,返回数组内容格式

package com.zheng.d3_string.stringbuilder;

public class StringBuilderTest2 {
    public static void main(String[] args) {
        int[] arr1 = null;
        System.out.println(toString(arr1));

        int[] arr2 = {10, 88, 99};
        System.out.println(toString(arr2));

        int[] arr3 = {};
        System.out.println(toString(arr3));
    }

    /**
       1、定义方法接收任意整型数组,返回数组内容格式
     */
    public static String toString(int[] arr){
       if(arr != null){
            // 2、开始拼接内容。
           StringBuilder sb = new StringBuilder("[");
           for (int i = 0; i < arr.length; i++) {
               sb.append(arr[i] ).append(i == arr.length - 1 ? "" : ", ");
           }
           sb.append("]");
           return sb.toString();
       }else {
           return null;
       }
    }
}

3. StringBuffer(线程安全)

3.1. 字符串拼接

package com.zheng.d3_string.stringbuffer.stringBuffer1;

public class Test1 {
    public static void main(String[] args) {
        long l1 = System.currentTimeMillis();
        // String完成字符串拼接
        /*String s ="asdf";
        for (int i = 0; i <1000000; i++) {
            s=s.concat("a");
        }*/
        //StringBuffer完成字符串拼接
        StringBuffer sbf =new StringBuffer("asdf");
        for (int i = 0; i <1000000; i++) {
            sbf.append("a");
        }
        long l2= System.currentTimeMillis();
        System.out.println(l2-l1);
    }
}

3.2. 字符串常见API(1)

package com.zheng.d3_string.stringbuffer.stringBuffer1;


public class Test2 {
    public static void main(String[] args) {
        StringBuffer sbf =new StringBuffer("asdf");
        // 当前存储的字符串长度
        System.out.println(sbf.length());
        // 当前StringBuffer内部数组的容量
        System.out.println(sbf.capacity());

        sbf.append("aaaaaaaaaaaaaaaaa");

        // 当前存储的字符串长度
        System.out.println(sbf.length());
        // 当前StringBuffer内部数组的容量
        System.out.println(sbf.capacity());
    }
}

3.3. 字符串常见API(2)

package com.zheng.d3_string.stringbuffer.stringBuffer2;

public class Test1 {
    public static void main(String[] args) {
        String str= "asdf";
        // 构造方法
        StringBuffer sbf=new StringBuffer(str);
        // 初始化容量
        StringBuffer sbf2 =new StringBuffer(32);

        // 删除
        StringBuffer s=new StringBuffer("asdfqwerzxcv");
        s.delete(4,8);
        System.out.println(s);
        s.deleteCharAt(3);
        System.out.println(s);

        // 插入
        s.insert(3,"uuuu");
        System.out.println(s);

        // 替换
        s.replace(3,7,"xxxx");
        System.out.println(s);

        // 翻转
        s.reverse();
        System.out.println(s);

        // 修改
        s.setCharAt(8,'V');
        System.out.println(s);

        // String 和Stringbuffer对象转换
        // String >>> StringBuffer  构造方法
        String str2 =s.toString();

        // 去除空余元素位
        StringBuffer sbf3 =new StringBuffer("asdf");
        System.out.println(sbf3.capacity());
        sbf3.trimToSize();
        System.out.println(sbf3.capacity());
    }
}

3.4. 追加字符串

package com.zheng.d3_string.stringbuffer.stringBuffer2;

public class Test2 {
    public static void main(String[] args) {
        StringBuffer sbf=new StringBuffer("asdf");
        sbf.append("asdf");
        StringBuilder sbd=new StringBuilder("asdf");
        sbd.append("asdf");

    }
}

3.5. 综合案例

package com.zheng.d3_string.stringbuffer.stringBuffer2;

public class Test3 {
    public static void main(String[] args) {
        int a=789;
        String binary = getBinary(a);
        System.out.println(binary);
        int integer = getInteger(binary);
        System.out.println(integer);
    }
    // 将1010字符串 转换为整数
    public static int getInteger(String num){
        int sum =0;
        for (int i = 0; i <num.length() ; i++) {
            char c = num.charAt(i);
            int j = Integer.parseInt(c + "");
            sum+=j*pow(2,num.length()-1-i);
        }
        return sum;
    }
    // 返回a的b次方
    public static int pow(int a,int b){
        // 3  5
        int j=1;
        for (int i = 0; i < b; i++) {
            j*=a;
        }
        return j;
    }


    // 将整数转化为1010字符串
    public static String getBinary(int num){
        StringBuilder sbd=new StringBuilder();
        while(num>0){
            int x =num%2;
            sbd.append(x);
            num/=2;
        }
        sbd.reverse();
        return sbd.toString();
    }
}

3.6. 是否为回文字符串

package com.zheng.d3_string.stringbuffer.stringBuffer2;

public class Test4 {
    public static void main(String[] args) {
        String s ="101010a1";
        StringBuilder sbd=new StringBuilder(s);
        sbd.reverse();
        String s2 = sbd.toString();
        System.out.println(s.equals(s2)?"是回文":"不是回文");
        
    }
}

3.7. 线程安全性

String 中的对象是不可变的,也就可以理解为常量,线程安全。

AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了 一些字符串的基本操作,如

expandCapacity、append、insert、indexOf 等公共方法。

StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以 是线程安全的。

StringBuilder 并没有对方法进行加同步锁,所以是非线程安全 的。

3.8. 性能

每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将 指针指向新的 String 对象。

StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。

相同情况下使用  StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不

安全的风险。

3.9. 总结

① 操作少量的数据 = String

② 单线程操作字符串缓冲区下操作大量数据 = StringBuilder

③ 多线程操作字符串缓冲区下操作大量数据 = StringBuffer

六、算法练习题

请阅读本人数据结构的字符串篇:常见基础算法题

七、详细面试问题

1. 字符型常量和字符串常量的区别

形式上: 字符常量是单引号引起的一个字符 字符串常量是双引号引起的 若干个字符

含义上: 字符常量相当于一个整形值( ASCII 值),可以参加表达式运算 字 符串常量代表一个地址值(该字符串在内存

中存放位置)

占内存大小: 字符常量只占 2 个字节 字符串常量占若干个字节(至少一个 字符结束标志) (注意: char 在Java中占

两个字节)

2. String & StringBuffer & StringBuilder 的区别

String StringBuffer 和 StringBuilder 的区别 是什么 String 为什么是不可变的

2.1. 可变性

简单的来说:String 类中使用 final 关键字字符数组保存字符串,private final char value[],所以 String 对象是

不可变的。

而 StringBuilder 与  StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中 也是使用

字符数组保存字符串char[] value 但是没有用 final 关键字修饰,所以 这两种对象都是可变的。

StringBuilder 与 StringBuffer 的构造方法都是调用父类构造方法也就是  AbstractStringBuilder 实现的,大家可

以自行查阅源码。

AbstractStringBuilder.java

abstract class AbstractStringBuilder implements Appendable, CharSequence { 
	char[] value; 
	int count; 
	AbstractStringBuilder() { 

	} 
	AbstractStringBuilder(int capacity) { 
		value = new char[capacity]; 
	}

2.2. 线程安全性

String 中的对象是不可变的,也就可以理解为常量,线程安全。

AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了 一些字符串的基本操作,如

expandCapacity、append、insert、indexOf 等公共方法。

StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁,所以 是线程安全的。

StringBuilder 并没有对方法进行加同步锁,所以是非线程安全 的。

2.3. 性能

每次对 String 类型进行改变的时候,都会生成一个新的 String 对象,然后将 指针指向新的 String 对象。

StringBuffer 每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象并改变对象引用。

相同情况下使用  StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不

安全的风险。

2.4. 总结

① 操作少量的数据 = String

② 单线程操作字符串缓冲区下操作大量数据 = StringBuilder

③ 多线程操作字符串缓冲区下操作大量数据 = StringBuffer

八、简洁面试问题

1. 怎样比较字符串?用”==”还是用equals()?

简单地说,”==”测试两个字符串的引用是否相同,equals()测试两个字符串的值是否相同。

除非你希望检查两个字符串是否是同一个对象,否则最好用equals()。

如果你知道字符串驻留机制会更好。

2. 为什么对于安全性敏感的信息char[]要优于String?

字符串是不变的,这也就意味着字符串一旦被创建,它们将一直保持在那直到被垃圾回收器清理为止。

而对于一个数组,你可以明确的修改它的元素。

这样一来,安全性敏感信息(比如密码)将不会出现在系统的任何其它地方。

3. 我们能不能在switch语句中使用String?

对于Java7答案是肯定的。从JDK7开始,我们可以使用String作为switch语句的条件。

在JDK6之前,我们不能使用String作为switch语句的条件。

// java 7 only!
switch (str.toLowerCase()) {
    case "a":
        value = 1;
        break;
    case "b":
        value = 2;
        break;
}

4. 怎样把字符串转换为整数?

int n = Integer.parseInt("10");

很简单,使用太过频繁以致有时候会被忽略。

5. 怎样分解一个有空白字符的字符串?

我们可以简单的用正则表达式来做分解。”\s”代表空白字符,例如” “,”\t”,”\r”,”\n”。

String[] strArray = aString.split("\\s+");

6. substring()方法真正做了什么?

在JDK6中,substring()方法提供了一个表示已有字符串的字符数组的窗口,但并没有创建一个新的字符串。

要创建一个由新的字符数组表示的新字符串,可以像下面一样添加一个空串:

str.substring(m, n) + ""

这样就创建一个表示新字符串的全新的字符数组。

上面的方法有时候会使代码更快,因为垃圾回收器会回收掉大的不用的字符串,只保留一个子串。

在Oracle JDK 7中,substring()创建一个新的字符数组,不用已有的数组。

The substring() Method in JDK 6 and JDK 7中的图表说明了JDK 6和JDK 7的substring()之间的差异。

7. String vs StringBuilder vs StringBuffer

String vs StringBuilder:StringBuilder是可变的,这意味着在创建之后人能够改变它的值。

StringBuilder vs StringBuffer:StringBuffer是同步的,这意味着它是线程安全的,但比StringBuilder更慢。

8. 怎样重复一个字符串?

在Python中,我们可以通过乘以一个数来重复字符串。

在Java中,我们可以通过Apache Commons Lang包中的StringUtils类的repeat()方法重复字符串。

String str = "abcd";
String repeated = StringUtils.repeat(str,3);
//abcdabcdabcd

9. 怎样把字符串转换为日期?

String str = "Sep 17, 2013";
Date date = new SimpleDateFormat("MMMM d, yy", Locale.ENGLISH).parse(str);
System.out.println(date);
//Tue Sep 17 00:00:00 EDT 2013

10. 怎样统计一个字符在字符串中出现的次数?

使用Apache Commons Lang包中的StringUtils类。

int n = StringUtils.countMatches("11112222", "1");
System.out.println(n);

11. Java String 值转化为boolean值

//把String 类型的true,转化为boolean类型的true
String intime="true";

boolean isIntime=Boolean.parseBoolean(intime);//结果为 isIntime=true

七、数据结构学习部门

 关注本人语雀字符串篇:字符串

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wclass-zhengge

你的鼓励是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值