String - Java

java.lang.String

创建字符串

直接赋值获取字符串:

1
String str = "Hello!"; // 字符串常量

字符串构造方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
String(); // 空字符串

String("Hello");

String​(String str)

String(char[] chs);

// 字节数组 (默认编码应该是ASCII
String(byte[] chs);
// 指定编码格式:
String​(byte[] bytes, String charsetName) // "UTF-8" "US-ASCII"
String​(byte[] bytes, Charset charset)

Java String 默认编码与运行环境有关

String​(byte[] bytes, int offset, int length) ,使用默认charset

String​(byte[] bytes, int offset, int length, Charset charset) 同上,但使用指定的charset

字节数组转换成字符串对象

字符串拼接优化

两个字符串常量拼接,在编译时会直接优化成拼接后的结果

1
2
3
String s1 = "hello";
// 等价于
String s2 = "hel" + "lo";

内存情况

字符串常量池

在JDK6.0及之前版本,字符串常量池存放在方法区中。自JDK7.0版本以后,字符串常量池被移到了堆Heap中了。
至于为什么移到Heap内,大概是由于方法区的内存空间太小了。

但是字符串常量池是区别于Heap的

直接赋值

直接使用字符串字面量赋值

String str = "Hello!";

存放在字符串常量池,如果常量池里没有同样的字符串,则创建一个,如果有同样的字符串,则直接指向

1
2
3
String str1 = "abc";
String str2 = "abc";
str1==str2; // true

new 对象 创建

存放在堆中,不会复用

1
2
3
4
5
6
7
8
String str1 = new String("abc");
String str2 = new String("abc");
str1 == str2; // false

char[] chs = {'a', 'b', 'c'};
String str3 = new String("abc"); // 根据字符数组,在堆中创建新的字符串
String str4 = new String("abc");
str3 == str4; // false

method

比较字符串

boolean equals​(Object anObject) 比较字符串内容,nullfalse
boolean equalsIgnoreCase​(String anotherString) 忽略英文大小写的比较

包含

boolean contains​(CharSequence s) 判断一个字符串里面是否包含指定的内容

获取指定部分

String substring​(int beginIndex, int endIndex) 左闭右开区间 获取指定部分

String substring​(int beginIndex) 获取到尾部

替换

不改变原字符串,返回一个替换后的新字符串

String replace​(char oldChar, char newChar) 将字符串中的oldChar,替换成newChar
String replace​(CharSequence target, CharSequence replacement) String实现了CharSequence接口

String replaceAll​(String regex, String replacement)

String replaceFirst​(String regex, String replacement)

拼接字符串

"Hello " + "world"

string1.concat("Hello");

String 拼接原理

1
2
String s1 = "a" + "b" + "c"; // 没有变量参与
String s2 = s1 + "d"; // 有变量参与
  • 当没有变量参与时
    • 字符串在编译时就优化为最终结果,等同于赋值最终结果
  • 当有变量参与时
    • JDK8前使用 StringBuilder 拼接,一个加号会创建两个对象(StringBuilder String)浪费性能
    • JDK8开始,默认拼接方案是,预估拼接的长度,创建一个长度合适的数组,填入字符串

结论:拼接字符串使用 StringBuilder 或 StringJoiner 效率较高,(减少中间商赚差价)

参数传递

String 是特殊的引用类型,参数传递可看作像基本类型一样的复制(?实际上仍是地址传递?),因为String不可更改,所以不用担心原字符串是否会被更改。

String 与其他类型的相互转换

数值

Double.parseDouble(str) String 解析成数值

String.valueOf(val) 其他类型转换成 String (包括一些非数值)

char

String to char

char charAt​(int index) String中指定位置的char

char[] toCharArray() char数组

char to String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1. String s = String.valueOf('c'); //效率最高的方法

2. String s = String.valueOf(new char[]{'c'}); //将一个char数组转换成String

3. String s = Character.toString('c');
// Character.toString(char)方法实际上直接返回String.valueOf(char)

4. String s = new Character('c').toString();

5. String s = "" + 'c';
// 虽然这个方法很简单,但这是效率最低的方法
// Java中的String Object的值实际上是不可变的,是一个final的变量。
// 所以我们每次对String做出任何改变,都是初始化了一个全新的String Object并将原来的变量指向了这个新String。
// 而Java对使用+运算符处理String相加进行了方法重载。
// 字符串直接相加连接实际上调用了如下方法:
// new StringBuilder().append("").append('c').toString();


6. String s = new String(new char[]{'c'});

// 上6条来自:https://www.cnblogs.com/rrttp/p/7922202.html

byte[]

byte[] b = str.getBytes(); String 转换成 byte 数组

查找

int indexOf​(int ch) 查找指定字符
int indexOf​(int ch, int fromIndex) 从指定索引开始向后的范围内
int indexOf​(String str) 字符串
int indexOf​(String str, int fromIndex)

int lastIndexOf​(int ch) 找到最后一次出现
int lastIndexOf​(int ch, int fromIndex) 从指定索引开始向后的范围内
int lastIndexOf​(String str)
int lastIndexOf​(String str, int fromIndex)

截取

截取子字符串:

String substring​(int beginIndex) 包含beginIndex
String substring​(int beginIndex, int endIndex) 不包含endIndex

左闭右开区间

其他 Method

int length() 字符数

boolean equals(Object obj) 比较字符串对象与当前对象是否相同

boolean startsWith​(String prefix) 是否以prefix开始
boolean startsWith​(String prefix, int toffset)