字符串
- java没有内置的字符串类型
- 在标准 Java 类库中提供的一个预定义类String
- 每个用双引号括起来的字符串都是 String 类的一个实例
子串
String.subString()方法
- 可以从一个较大的字符串提取出一个子串
String greeting = "hello";
//提取字符串中位置从0到2的子字符串(不包含3)
String s = greeting.subString( 0, 3);
System.out.println(s);
输出:
hel
拼接
java可以利用‘+’进行拼接
字符串与字符串之间的拼接
String expletive = "Expletive";
String PC13 = "deleted";
String message = expletive + PC13;
System.out.println(message);
输出
Expletivedeleted
注意:中间没有空格
字符串与非字符串之间的拼接
非字符串会被转换成字符串
例1:
int age = 13;
String rating = "PG" + age;
System.out.println(rating);
输出:
PG13
这种特性通常用在输出语句中
例2:
System.out.println("The answer is " + answer) ;
使用定界符分割的拼接
- 使用静态join方法
String all = String.join(" / ", "S", "M", "L", "XL");
System.out.println(all);
输出
S / H / L / XL
不可变字符串
java 文档中将 String 类对象称为不可变字符串
原因:
- String 类没有提供用于修改字符串的方法
那么如何修改字符串呢?
例:
//将greeting字符串修改为"help!"
String greeting = "hello";
greeting = greeting.substring(0, 3) + "p!";
System.out.println(greeting);
输出
help!
操作:
- 提取需要的字符
- 再拼接上替换的字符串
那这么做是否会降低运行效率呢?
答案是:也对,也不对。
通过拼接创建新的字符串效率确实不高,但是却可以让字符串共享。
可以想象将各种字符串存放在公共的存储池中,字符串变量指向存储池中相应的位置。 如果复制一个字符串变量, 原始字符串与复制的字符串共享相同的字符。
总而言之, Java 的设计者认为共享带来的高效率远远胜过于提取、 拼接字符串所带来的低效率。
检测字符串是否相等
s.equals(t)
- 检测两个字符串s和t是否相等,区分大小写
- 如果相等,返回true
- 如果不等,返回false
- 其中s和t可以是字符串变量,也可以是字符串常量
s.equalsIgnoreCase(t)
- 检测两个字符串s和t是否相等,且不区分大小写
一定不要使用"=="运算符检测两个字符串是否相等
==
- 这个运算符只能够确定两个字串是否放置在同一个位置上
当然, 如果字符串放置在同一个位置上, 它们必然相等。但是, 完全有可能将内容相同的多个字符串的拷贝放置在不同的位置上
//initialize greeting to a string
String greeting = "Hello";
if (greeting == "Hello")
// probably true
... ...
if (greeting.substring(0, 3) == "Hel")
// probably false
... ...
- 如果虚拟机始终将相同的字符串共享
- 就可以使用"=="运算符检测是否相等
- 但实际上只有字符串常量是共享的
- 而 + 或 substring 等操作产生的结果并不是共享的
因此, 千万不要使用 “==” 运算符测试字符串的相等性, 以免在程序中出现糟糕的bug
空串与null串
空串
- 长度为0的字符串
- 是一个 Java 对象, 有自己的串长度(0 ) 和内容(空)
检测方式:
if (str.length() = 0 || if (str.equals(""))){
... ...
}
null值
- String 变量还可以存放一个特殊的值
- 表示目前没有任何对象与该变量关联
检测方式:
if (str == null){
... ...
}
有时要检查一个字符串既不是 null 也不为空串, 这种情况下就需要使用以下条件:
if (str != null && str.length() != 0){... ...}
首先要检查 str 不为 null
码点和代码单元
java字符串由char值序列组成
char数据类型:
- 一个采用 UTF-16 编码表示 Unicode 码点的代码单元
其中
码点 ( code point ) 是指与一个编码表中的某个字符对应的代码值
- 在 Unicode 标准中, 码点采用十六进制书写,并加上前缀U+,
- 例如U+0041就是拉丁字母A的码点
更详细的介绍可参考Java中码点和代码单元这篇文章。
可以引用其中的一个小例子来感受一下
public static void main(String[] args) { String hello = "hi𝕆"; System.out.println(hello.length());//4 System.out.println(hello.codePointCount(0, hello.length()));//3 }
其中 length方法将返回采用 UTF-16 编码表示的给定字符串所需要的代码单元数量:
String greeting = "Hello";
int n = greeting.length();
//输出位5
如果想得到实际的长度, 即码点数量, 可以调用
int cpCount = greeting.codePointCount(0, greeting.length());
调用 s.charAt(n) 将返回位置 n 的代码单元, n 介于 0 ~ s.length()-l 之间
char first = greeting.charAtO); // first is 'H'
String API
Java 中的 String 类包含了50多个方法
令人惊讶的是绝大多数都很有用,下面简单介绍一些常用的API
api 接口 | 说明 |
---|---|
char charAt(int index) | 返回给定位置的代码单元。 除非对底层的代码单元感兴趣, 否则不需要调用这个方法。 |
int codePointAt( int Index) | 返回从给定位置开始的码点 |
int compareTo(String other) | 按照字典顺序, 如果字符串位于 other 之前, 返回一个负数; 如果字符串位于 other 之后, 返回一个正数; 如果两个字符串相等, 返回 0。 |
IntStream codePoints() | 将这个字符串的码点作为一个流返回。 调用 toArray 将它们放在一个数组中。 |
new String(int[] codePoints, int offset, int count) | 用数组中从 offset 开始的 count 个码点构造一个字符串 |
boolean equals(0bject other) | 如果字符串与 other 相等, 返回 true。 |
boolean equalsIgnoreCase(String other) | 如果字符串与 other 相等 (忽略大小写,) 返回 true |
boolean startsWith(String prefix) boolean endsWith(String suffix) | 如果字符串以 suffix 开头或结尾, 则返回 true。 |
int indexOf(String str) int indexOf(String str, int fromlndex) int indexOf(int cp) int indexOf(int cp, int fromlndex) | 返回与字符串 str 或代码点 cp 匹配的第一个子串的开始位置。这个位置从索引 0 或 fromlndex 开始计算。 如果在原始串中不存在 st,r 返回 - 1。 |
int 1astIndexOf(String str) Int 1astIndexOf(String str, int fromlndex) int lastindexOf(int cp) int lastindexOf(int cp, int fromlndex) | 返回与字符串 str 或代码点 cp 匹配的最后一个子串的开始位置。 这个位置从原始串尾端或 fromlndex 开始计算。 |
int length( ) | 返回字符串的长度 |
int codePointCount(int startlndex, int endlndex) | 返回 startlndex 和 endludex- l 之间的代码点数量。 没有配成对的代用字符将计入代码点 |
String replace(CharSequence oldString,CharSequence newString) | 返回一个新字符串。 这个字符串用 newString 代替原始字符串中所有的 oldString。 可 以用 String 或 StringBuilder 对象作为 CharSequence 参数 |
String substring(int beginlndex) String substring(int beginlndex, int endlndex) | 返回一个新字符串。这个字符串包含原始字符串中从 beginlndex 到串尾或 endlndex-l |
的所有代码单元。 | |
String toLowerCase( ) String toUpperCase( ) | 返回一个新字符串。 这个字符串将原始字符串中的大写字母改为小写, 或者将原始字符串中的所有小写字母改成了大写字母。 |
String trim( ) | 返回一个新字符串。 这个字符串将删除了原始字符串头部和尾部的空格。 |
String join(CharSequence delimiter, CharSequence… elements) | 返回一个新字符串, 用给定的定界符连接所有元素 |
在 API 注释中, 有一些 CharSequence 类型的参数, 现在只需要知道只要看到 一个 CharSequence 形参, 完全可以传入 String 类型的实参
构建字符串
出现的问题
- 需要由较短的字符串构建字符串
- 采用字符串连接的方式达到此目的效率比较低
- 每次连接字符串, 都会构建一个新的 String 对象
解决方案
- 使用 StringBuilder 类
步骤
//1. 构建一个空的字符串构建器
StringBuilder builder = new StringBuilder();
//2. 当每次需要添加一部分内容时, 就调用 append 方法
builder.append(ch); // appends a single character
bui1der.append(str); // appends a string
//3. 在需要构建字符串时就凋用 toString 方法, 将可以得到一个 String 对象
String completedString = builder.toStringO;
StringBuilder类的前身是 StringBuffer, 其效率稍有些低, 但允许采用多线程的方式执行添加或删除字符的操作。 如果所有字符串在一个单线程中编辑 (通常都是这样) , 则应该用 StringBuilder 替代它
参考
java核心卷1