Java 字符串
String 类
String 概述
-
String 类在 java.lang 包下,所以使用的时候不需要导包。
-
String 类代表字符串,Java 程序中的所有字符串文字(例如"abc")都被实现为此类的实例。也就是说,Java 程序中所有的双引号字符串,都是 String 类的对象。
-
字符串不可变,它们的值在创建后不能被更改。
-
String 这个类比较特殊,打印其对象名的时候,不会出现内存地址,而是该对象所记录的真实内容。
字符串的创建
String 类的创建有两种方式:一种是直接使用双引号赋值,另一种是使用 new 关键字创建对象。
1)直接创建:
String 字符串名 = "字符串内容";
2)使用 new 关键字创建:
String 类有多种重载的构造方法,具体如下:
String()
:创建一个空内容的字符串对象。String(byte[] bytes)
:使用一个字节数组构建一个字符串对象。String(byte[] bytes, int offset, int length)
:使用一个字节数组构建一个字符串对象,并指定开始的索引值与解码的个数。- offset:指定从数组中哪个索引值开始解码。
- length:要解码多少个元素。
String(char[] value)
:使用一个字符数组构建一个字符串对象。String(char[] value, int offset, int count)
:使用一个字符数组构建一个字符串对象,并指定开始的索引值与解码的个数。String(int[] codePoints, int offset, int count)
:与字节数组一样用法。String(String original)
:用字符串构建字符串对象。
public class StringConstructor {
public static void main(String[] args) {
// public String():创建一个空白字符串对象,不含有任何内容
String s1 = new String();
System.out.println(s1); // ""
// public String(char[] chs):根据字符数组的内容,来创建字符串对象
char[] chs = {'a', 'b', 'c'};
String s2 = new String(chs);
System.out.println(s2); // "abc"
// public String(String original):根据传入的字符串内容,来创建字符串对象
String s3 = new String("123");
System.out.println(s3); // "123"
}
}
创建字符串对象的区别对比:
-
通过构造方法创建:通过 new 创建的字符串对象,每一次 new 都会申请一个内存空间,且即时内容相同,地址值也不同。
-
直接赋值方式创建:以 "" 方式给出的字符串,只要字符序列相同(顺序和大小写),无论在程序代码中出现几次,JVM 都只会存在一个该 String 对象,并在字符串池中维护。
字符串的比较:
==
:比较基本数据类型时,比较的是值内容;比较引用数据类型时,比较的是对象地址。- String 类的 public boolean
equals(String s)
:比较两个字符串的值内容是否相同。
public static void test(String str){
// 使用技巧:str 有可能指向空(null)对象,放前面的话可能会出现空指针异常。
// 因此常将常量放前面作为 equals 的调用者,杜绝空指针异常。
if("中国".equals(str)){
System.out.println("回答正确");
}else{
System.out.println("回答错误");
}
}
String 常用方法
获取方法 | 说明 |
---|---|
int length() | 获取字符串的长度 |
char charAt(int index) | 返回指定索引处的 char 值 |
int indexOf(String str) | 查找子串第一次出现的索引值。若子串不存在,则返回 -1 |
indexOf(String str, int fromIndex) | 从指定的索引值开始查找子串 |
int lastIndexOf(String str) | 返回指定子字符串在此字符串中最右边出现处的索引,如果此字符串中没有这样的字符,则返回 -1 |
int lastIndexOf(String str, int fromIndex) | 返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索,如果此字符串中没有这样的字符,则返回 -1 |
String concat(String str) | 实现将一个字符串(参数 str)连接到另一个字符串后面 |
判断方法 | 说明 |
---|---|
boolean startsWith(String str) | 是否以指定字符开头 |
boolean endsWith(String str) | 是否以指定字符结束 |
boolean isEmpty() | 是否长度为 0 |
boolean contains(charSequences) | 是否包含子串 (多态:charSequences 参数属于接口,String 是它的实现类) |
boolean equals(Object anObject) | 判断两个字符串的内容是否一致 |
boolean equalsIgnoreCase(String anotherString) | 忽略大小写,判断两个字符串的内容是否一致 |
boolean matches(String regex) | 进行正则表达式的验证,若匹配则返回 true |
操作方法 | 说明 |
---|---|
String replace(CharSequence target, CharSequence replacement) | 将字符串中的旧值替换成新值,得到新的字符串 |
String[] split(String regex) | 根据指定的字符进行切割 |
String substring(int beginIndex) | 从传入的索引处截取,截取到末尾,得到新的字符串 |
public String substring(int beginIndex, int endIndex) | 根据开始和结束索引进行截取,得到新的字符串(包头不包尾) |
String toUpperCase() | 转大写 |
String toLowerCase() | 转小写 |
String trim() | 去掉字符串前后的空格字符 |
数组转换方法 | 说明 |
---|---|
Char[] toCharArray() | 将字符串转换为字符数组 |
Byte[] getBytes() | 将字符串转换为字节数组 |
示例:
public static void main(String[] args) {
// 字符串转数组
byte[] a = "abc".getBytes();
char[] b = "abc".toCharArray();
System.out.println(a); // [B@1b6d3586
System.out.println(b); // abc
// 数组的字符串表示形式
System.out.println(Arrays.toString(a)); // [97, 98, 99]
System.out.println(Arrays.toString(b)); // [a, b, c]
// 数组转字符串
StringBuffer stringBuffer = new StringBuffer();
for (char s : b) {
stringBuffer.append(s + "");
}
System.out.println(stringBuffer.toString());
}
字符串的类型转换
数据类型 | 字符串转其他数据类型的方法 | 其他数据类型转字符串的方法1 | 其他数据类型转字符串的方法2 |
---|---|---|---|
byte | Byte.parseByte(str) | String.valueOf(byte bt) | Byte.toString(byte bt) |
int | Integer.parseInt(str) | String.valueOf(int i) | Int.toString(int i) |
long | Long.parseLong(str) | String.valueOf(long l) | Long.toSting(long l) |
double | double.parseDouble(str) | String.valueOf(double d) | Double.toString(double b) |
float | Float.parseFloat(str) | String.valueOf(float f) | Float.toString(float f) |
char | str.charAt(int index) | String.valueOf(char c) | Character.toString(char c) |
boolean | Boolean.getBoolean(str) | String.valueOf(boolean b) | Boolean.toString(boolean b) |
char[] | str.toCharArray() | String(char[] value) | 遍历字符元素进行字符串拼接 |
byte[] | str.getBytes() | String(byte[] value) | 遍历字节元素进行字符串拼接 |
String 类不可变的好处
-
不可变对象可以
提高 String Pool(字符串常量池)的效率
。如果知道一个对象是不可变的,那么需要复制对象的内容时不用复制它本身而只是复制它的地址,复制地址(通常一个指针的大小)只需要很小的内存,效率也很好。同时,对其他引用同一个对象的变量也不会造成影响。 -
因为字符串时不可变的,所以是
线程安全
的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。 -
因为字符串是不可变的,所以在创建它的时候
哈希码就被缓存了,不需要重新计算
。这就使得字符串很适合作为 Map 中的键,字符串的处理速度要快过其他键对象。这就是 HashMap 中的键往往都使用字符串的原因。
格式化字符串的方法
String.format() 方法使用指定的格式字符串和参数,并返回一个格式化字符串。
1)常规类型格式化:format(String format, Object…args)
- format:格式字符串。
- args:格式字符串中由格式说明符引用的参数。参数数目是可变的(可以为 0)。
转换符 | 说 明 | 示例 |
---|---|---|
%b、%B | 格式化为布尔类型 | false |
%h、%H | 格式化为哈希码 | A05A5198 |
%s、%S | 格式化为字符串类型 | "abc" |
%c、%C | 格式化为字符类型 | 'w' |
%d | 格式化为十进制数 | 26 |
%0 | 格式化为八进制数 | 12 |
%x、%X | 格式化为十六进制数 | 4b1 |
%e | 格式化为用计算机科学计数法表示 的十进制数 | 1.700000e+01 |
%a | 格式化为带有效位数和指数的十六 进制浮点值 | 0X1.C000000000001P4 |
示例:
String s1 = String.format("%d", 400/2); // 200
String s2 = String.format("%b", 3>5); // false
2)日期时间格式化:format(Locale, String format, Object…args)
- Locale:格式化过程中要应用的语言环境。如果为空则不进行本地化。
- format:格式字符串。
- args:格式字符串中由格式说明符引用的参数。如果还有格式说明符以外的参数,则忽略这些额外的参数。参数的数目是可变的,可以为 0。
转换符 | 说明 | 示例 |
---|---|---|
%te | 一个月中的某一天(1~31) | 12 |
%tb | 指定语言环境的月份简称 | Jan(英文)、一月(中文) |
%tB | 指定语言环境的月份全称 | February(英文)、二月(中文) |
%tA | 指定语言环境的星期几全称 | Monday(英文)、星期一(中文) |
%ta | 指定语言环境的星期几简称 | Mon(英文)、星期一(中文) |
%tc | 包括全部日期和时间信息 | 星期三十月 25 13:37:22 CST 2008 |
%tY | 4 位年份 | 2008 |
%tj | 一年中的第几天(001~366) | 060 |
%tm | 月份 | 05 |
%td | 一个月中的第几天(01~31) | 07 |
%ty | 两位年份 | 08 |
示例:
Date date = new Date();
Locale form = Locale.US;
String year = String.format(form, "%tY", date);
String month = String.format(form, "%tB", date);
String day = String.format(form, "%td", date);
System.out.println("当前年份:"+year); // 当前年份:2021
System.out.println("当前月份:"+month); // 当前月份:November
System.out.println("当前日份:"+day); // 当前日份:06
StringBuffer 类
StringBuffer 概述
回顾字符串的特点:
- 字符串是常量,它们的值在创建之后不能更改。
- 字符串的内容一旦发生了变化,那么马上会创建一个新的对象。
因此,字符串的内容不适宜频繁修改,因为一旦修改马上就会创建一个新的对象。所以如果需要修改字符串的内容,建议使用字符串缓冲类——StringBuffer:一个存储字符的容器
。
StringBuffer 底层是依赖一个字符数组才能存储字符数据的,该字符数组默认的初始容量是 16。如果字符数组的长度不够用,自动增长一倍(再加 2)。
StringBuffer 常用方法
添加方法 | 说明 |
---|---|
StringBuffer append(String/boolean/...) | 可以添加任意类型的数据到容器中 |
StringBuffer insert(int offset, boolean/...) | 指定索引值位置来插入数据 |
删除方法 | 说明 |
---|---|
StringBuffer delete(int start, int end) | 指定开始索引值与结束索引值来删除容器中的数据 |
StringBuffer deleteCharAt(int index) | 指定索引值删除一个字符 |
修改方法 | 说明 |
---|---|
StringBuffer replace(int start, int index, String str) | 指定开始索引值与结束索引值替换新的字符串内容 |
StringBuffer reverse() | 翻转内容 |
void setCharAt(int index, char ch) | 指定索引位替换字符 |
String substring(int start, int end) | 指定开始索引值与结束索引值截取内容 |
void ensureCapacity(int minimunCapacity) | 指定字符串缓冲类的字符数组长度(基本不用) |
String toString() | 把字符串缓冲类的内容转换成字符串 |
查询方法 | 说明 |
---|---|
indexOf(String str, int fromIndex) | 查找子串第一次出现的索引值 |
lastIndexOf(String str) | 查找子串最后一次出现的索引值 |
capacity() | 查询当前(底层)字符数组的长度 |
length() | 查询当前字符串长度 |
charAt(int Index) | 根据索引值查询字符 |
StringBuilder 类
StringBuilder 概述
StringBuilder 也是一个可变的字符串类,我们可以把它看成是一个容器,这里的可变指的是StringBuilder 对象中的内容是可变的
。
StringBuilder 常用方法与 StringBuffer 常用方法一致。
public class Test{
public static void main(String[] args) {
// 创建对象
StringBuilder sb = new StringBuilder();
// public StringBuilder append(任意类型):添加数据,并返回对象本身
// StringBuilder sb2 = sb.append("hello");
//
// System.out.println("sb:" + sb);
// System.out.println("sb2:" + sb2);
// System.out.println(sb == sb2);
// sb.append("hello");
// sb.append("world");
// sb.append("java");
// sb.append(100);
// 链式编程
sb.append("hello").append("world").append("java").append(100);
System.out.println("sb:" + sb); // helloworldjava100
// public StringBuilder reverse():返回逆序的字符序列
sb.reverse();
System.out.println("sb:" + sb); // 001avajdlrowolleh
// StringBuilder 转换为 String
StringBuilder sb2 = new StringBuilder();
sb2.append("hello");
String s2 = sb2.toString();
System.out.println(s2);
// String 转换为 StringBuilder
String s3 = "hello";
StringBuilder sb3 = new StringBuilder(s2);
System.out.println(sb2);
}
}
String、StringBuffer、StringBuilder 对比
-
String 为字符串常量,而 StringBuffer、StringBuilder 均为字符串变量,即 String 一旦创建之后该对象是不可更改的,但后两者的对象是变量,是可以更改的。
-
StringBuffer 是线程安全的,而 StringBuilder 则没有实现线程安全,因此执行速度较高。
- 一个 StringBuffer 对象在字符串缓冲区被多个线程使用时,其很多方法都带有 Synchronized 关键字,所以可以保证线程是安全的;而 StringBuilder 的 append() 方法中则没有 Synchronized 关键字,所以不能保证线程安全。
- 因此如果要进行的操作是多线程的,那么建议使用 StringBuffer;单线程下则建议使用速度较快的 StringBuilder。