String

122 阅读2分钟

不可变性

由于不能修改Java字符串中的单个字符,所以在Java文档中将String类对象称为是不可变的(immutable)。

如同数字3永远是数字3一样,字符串"Hello"永远包含字符H、e、1、1和o的代码单元序列。你不能修改这些值,不过,可以修改字符串变量 greeting,让它引用另外一个字符串,这就如同可以让原本存放3的数值变量改成存放4一样。

相等性

一定不要使用==运算符检测两个字符串是否相等!

这个运算符只能够确定两个字符串是否存放在同一个位置上。当然,如果字符串在同一个位置上,它们必然相等。但是,完全有可能将内容相同的多个字符串副本放置在不同的位置上。

String greeting ="Hello"; // initialize greeting to a string 
if (greeting == "Hello")....
// probably true
if(greeting.substring(8,3)=="Hel")...
// probably false

由于虚拟机只共享了字符串字面量,而+或substring等操作得到的字符串并不共享。因此,千万不要使用=运算符测试字符串的相等性,以免在程序中出现这种最糟糕的bug,看起来这种bug就像随机产生的间歇性错误。

码点与代码单元

Java字符串由char值序列组成。从Java基本数据类型知道,char数据类型是一个采用UTF-16编码表示Unicode码点的代码单元。最常用的Unicode字符使用一个代码单元就可以表示,而辅助字符需要一对代码单元表示。 length方法将返回采用UTF-16编码表示给定字符串所需要的代码单元数量。

记得之前看到过关于length含义的面试题,大家可以稍微关注下这个知识点

例如:

String greeting = "Hello";int n=greeting.length();// is 5

要想得到实际的长度,即码点数量,可以调用:

int cpCount = greeting.codePointCount(0,greeting.length();

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

char first = greeting.charAt(0); // first is 'H'
char last = greeting.charAt(4);// last is 'o'

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

int index = greeting.offsetByCodePoints(8,i);int cp = greeting.codePointAt(index);

为什么会对代码单元如此大惊小怪?请考虑以下语句:

🏀 is the set of octonions.

使用UTF-16编码表示字符🏀(U+1F3C0)需要两个代码单元。调用char ch = sentence.charAt(1) 返回的不是一个空格,而是🏀的第二个代码单元。为了避免这个问题,不要使用char类型。 要查看代码点,可以使用下面的方式:

//10进制
s.codePoints().forEachOrdered(System.out::println);
//16进制,在前边加上U+即是Unicode编码
s.codePoints().forEachOrdered(e -> System.out.println(Integer.toHexString(e)));

或者要查看一个代码点序列表示的字符串:

int[] codePoints = s.codePoints().toArray();
System.out.println(new String(codePoints, 0, codePoints.length));