2.1 Java 字符串

188 阅读5分钟

Java 字符串就是 Unicode 字符序列

1. 子串

String 类的 substring 方法可以从一个较大的字符串提取出一个子串。

substring(开始,结尾(不包括))

String str="123456"; 
System.out.println(str.substring(1,3)); //23

2. 拼接

可以使用 + 拼接,字符串和其他类型也可以拼接

int age = 13; 
String str="哈哈"; 
String rating = "PC" + age+str+true;

3. 不可变字符串

String 类没有提供用于修改字符串的方法。由于不能修改 Java 字符串中的字符, 所以在 Java 文档中将 String 类对象称为不可变字符串,如同数字 3 永远是数字 3 一样,字符串“ Hello” 永远包含字符 H、e、1、1 和 o 的代码单元序列,而不能修改其中的任何一个字符。

当然,可以修改字符串变量 greeting, 让它引用另外一个字符串, 这就如同可以将存放 3 的数值变量改成存放 4 一样。

4. String变量每次改变都会产生一个字符串,是否会降低运行效率?

看起来好像修改一个代码单元要比创建一个新字符串更加简洁, 但是不可变字符串却有一个优点:编译器可以让字符串共享。字符串存储在常量池中,每个String 变量都指向常量池中的地址。

Java 的设计者认为共享带来的高效率远远胜过于提取、 拼接字符串所带来的低效率。查看一下程序会发现:很少需要修改字符串, 而是往往需要对字符串进行比较(有一种例外情况,将来自于文件或键盘的单个字符或较短的字符串汇集成字符串。为此, Java提供了一个独立的类,字符流相关)

5. 字符串的比较

可以使用 equals 方法检测两个字符串是否相等 ,可以使用equals()方法。如果字符串 s 与字符串 t 相等, 则返回 true ; 否则, 返回 false。s与 t 可以是字符串变量,也可以是字符串字面量。

s.equals(t); 
"java".equals("java");

如果想比较两个字符串不区分大小写是否相等

"Hello".equalsIgnoreCase("hello");

字符串比较时,不要使用==,== 只是比较字符串是否在同一地址上,如果同样的字符串拷贝到不同位置,那么即使字符串是一样,但是== 返回的也是false

String greeting = "Hello"; if (greeting == "Hello") //true 
if (greeting.substring(0, 3) == "Hel) //false

如果虚拟机始终将相同的字符串共享, 就可以使用=运算符检测是否相等。但实际上只有字符串常量是共享的,而 + 或 substring 等操作产生的结果并不是共享的。

6. 空串和null串

空串 "" 是长度为 0 的字符串。可以调用以下代码检查一个字符串是否为空。

if (str.length()) == 0) if (str.equals(""))

空串是一个 Java 对象, 有自己的串长度( 0 ) 和内容(空)。不过, String 变量还可以存放一个特殊的值, 名为 null, 这表示目前没有任何对象与该变量关联。

要检查一个字符串是否为 null, 要使用以下条件:

if (str == null)

有时要检查一个字符串既不是 null 也不为空串,首先要检查 str 不为 null。这种情况下就需要使用以下条件:

if (str != null && str.length()) != 0)

7. 码点与代码单元

Java 字符串由 char 值序列组成。char 数据类型是一个采用 UTF-16 编码表示 Unicode 码点的代码单元。大多数的常用 Unicode 字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。

length 方法将返回采用 UTF-16 编码表示的给定字符串所需要的代码单元数量。

String str = "Hello"; int n = str.length。; // is 5 .

要想得到实际的长度,即码点数量,

str.codePointCount(0,str.length())

调用 s.charAt(n) 将返回位置 n 的代码单元,n 介于 0 ~ s.length()-l 之间。例如:

char first = str.charAtO); // first is 'H' char last = str.charAt(4); // last is ’o’

要想得到第 i个码点,应该使用下列语句

int index = str.offsetByCodePoints(0, i); int cp = str.codePointAt(index);

为什么会对代码单元如此大惊小怪? 使用 UTF-16 编码表示字符⑪(U+1D546) 需要两个代码单元。调用char ch = sentence.charAt(l)返回的不是一个空格,而是⑪的第二个代码单元。为了避免这个问题, 不要使用 char 类型。这太底层了。

如果想要遍历一个字符串,并且依次査看每一个码点, 可以使用下列语句:

int cp = sentence.codePointAt(i); //isSupplementaryCodePoint 是否是补充码点 
if (Character.isSupplementaryCodePoint(cp)) i+= 2; else i++;

可以使用下列语句实现回退操作:

i--; //Character.isSurrogate()是否是代理 
if (CharacterssSurrogate(sentence.charAt(i))) i--; 
int cp = sentence.codePointAt(i);

显然, 这很麻烦。更容易的办法是使用 codePoints 方法, 它会生成一个 int 值的“ 流”,每个 int 值对应一个码点。 可以将它转换为一个数组再完成遍历。

int[] codePoints = str.codePoints()).toArray();

反之,要把一个码点数组转换为一个字符串, 可以使用构造函数(我们将在第 4 章详细讨论构造函数和 new 操作符 )。

String str = new String(codePoints, 0, codePoints.length);

8. 构建字符串

采用字符串拼接方式每次都会构建一个新的 String 对象,既耗时, 又浪费空间。使用 StringBuilder类就可以避免这个问题的发生。在需要构建字符串时仅调用 toString 方法, 将可以得到一个 String 对象, 其中包含了构建器中的字符序列。

StringBuilder builder = new StringBuilder(); 
builder.append(ch); // 拼接一个字符 builder.append(str); // 拼接另一个字符串 String completedString = builder.toString();

在 JDK5.0 中引入 StringBuilder 类。 这个类的前身是 StringBuffer, 其效率稍有些低, 但允许采用多线程的方式执行添加或删除字符的操作 。 如果所有字符串在一个单线程中编辑 (通常都是这样) , 则应该用 StringBuilder 替代它。 这两个类的 AP丨是相同的。

StringBuilder 类中的重要方法:

image.png

9. String 常用API

image.png

image.png

image.png