String
String特点
- String 被 final 修饰,不可被继承,并且它的成员方法都默认为 final 方法
- String 通过 char 数组存储字符数据
String str = "abc"; 等效于: char data[] = {'a', 'b', 'c'}; String str = new String(data);
String源码
成员变量
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** 字符存储 */
private final char value[];
/** 缓存字符串的哈希代码 */
private int hash; // Default to 0
}
构造方法
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/**
* 初始化新创建的 String 对象(空字符序列)
* 由于字符串是不可变的,因此不需要使用此构造函数
* @return [description]
*/
public String() {
this.value = "".value;
}
/**
* 初始化的字符串是参数 original 字符串的副本
* @param original [description]
* @return [description]
*/
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
/**
* 将 value[] 分配到 String
* 对字符数组的后续修改不会影响新创建的字符串
* @param value[] [description]
* @return [description]
*/
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
/**
* 从 codePoints[] 的索引为 offset 开始截取长度为 length 的子串为 String 类
* 对字符数组的后续修改不会影响新创建的字符串
* @param value[] 作为字符源的数组
* @param offset 初始偏移量,子数组第一个字符的索引
* @param count 子数组的长度
* @return [description]
*/
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
/**
* 创建编码格式为 Unicode,从 codePoints[] 的索引为 offset 开始截取长度为 length 的子串为 String 类
* @param codePoints Unicode code Points 数组
* @param offset 初始偏移量,子数组第一个字符的索引
* @param count 子数组的长度
* @return [description]
*/
public String(int[] codePoints, int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= codePoints.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > codePoints.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
final int end = offset + count;
// Pass 1: Compute precise size of char[]
int n = count;
for (int i = offset; i < end; i++) {
int c = codePoints[i];
if (Character.isBmpCodePoint(c))
continue;
else if (Character.isValidCodePoint(c))
n++;
else throw new IllegalArgumentException(Integer.toString(c));
}
// Pass 2: Allocate and fill in char[]
final char[] v = new char[n];
for (int i = offset, j = 0; i < end; i++, j++) {
int c = codePoints[i];
if (Character.isBmpCodePoint(c))
v[j] = (char)c;
else
Character.toSurrogates(c, v, j++);
}
this.value = v;
}
/**
* 创建编码格式为 ascii,从 ascii[] 的索引为 offset 开始截取长度为 length 的子串为 String 类
* @param ascii[] ascii[] 数组
* @param hibyte [description]
* @param offset 初始偏移量,子数组第一个字符的索引
* @param count 子数组的长度
* @return [description]
*/
@Deprecated
public String(byte ascii[], int hibyte, int offset, int count) {
checkBounds(ascii, offset, count);
char value[] = new char[count];
if (hibyte == 0) {
for (int i = count; i-- > 0;) {
value[i] = (char)(ascii[i + offset] & 0xff);
}
} else {
hibyte <<= 8;
for (int i = count; i-- > 0;) {
value[i] = (char)(hibyte | (ascii[i + offset] & 0xff));
}
}
this.value = value;
}
@Deprecated
public String(byte ascii[], int hibyte) {
this(ascii, hibyte, 0, ascii.length);
}
/**
* 创建编码格式为 charsetName,从 bytes[] 的索引为 offset 开始截取长度为 length 的子串为 String 类
* @param bytes[] 要解码为字符的字节
* @param offset 要解码的第一个字节的索引
* @param length 要解码的字节数
* @param charsetName 支持的 ava.nio.charset.charset 名称
* @return [description]
* @throws UnsupportedEncodingException 如果不支持命名字符集
*/
public String(byte bytes[], int offset, int length, String charsetName) throws UnsupportedEncodingException {
if (charsetName == null)
throw new NullPointerException("charsetName");
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(charsetName, bytes, offset, length);
}
public String(byte bytes[], int offset, int length, Charset charset) {
if (charset == null)
throw new NullPointerException("charset");
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(charset, bytes, offset, length);
}
/**
* 将 bytes[] 转化为编码格式为 charsetName 的 String 类
* @param bytes[] [description]
* @param charsetName [description]
* @return [description]
* @throws UnsupportedEncodingException [description]
*/
public String(byte bytes[], String charsetName) throws UnsupportedEncodingException {
this(bytes, 0, bytes.length, charsetName);
}
public String(byte bytes[], Charset charset) {
this(bytes, 0, bytes.length, charset);
}
/**
* 创建默认编码格式 ISO-8859-1,从 bytes[] 的索引为 offset 开始截取长度为 length 的子串为 String 类
* @param bytes[] [description]
* @param offset [description]
* @param length [description]
* @return [description]
*/
public String(byte bytes[], int offset, int length) {
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(bytes, offset, length);
// String csn = Charset.defaultCharset().name(); ...
// return decode("ISO-8859-1", ba, off, len); ...
}
/**
* 创建默认编码格式 ISO-8859-1 为 String 类
* @param bytes[] [description]
* @return [description]
*/
public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}
/**
* 将 StringBuffer 转化为 String
* @param buffer [description]
* @return [description]
*/
public String(StringBuffer buffer) {
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
/**
* 将 StringBuilder 转化为 String
* @param builder [description]
* @return [description]
*/
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}
/**
* share 提升速度
*/
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
}
字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池 。创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于 String 字符串的不可变性,可以十分肯定常量池中一定不存在两个相同的字符串
public class stringDemo {
public static void main(String[] args) {
String str0 = "abc";
String str1 = "abc";
String str2 = new String();
char[] charArray = { 'a', 'b', 'c' };
String str3 = new String(charArray);
byte[] byteArray = { 97, 98, 99 };
String str4 = new String(byteArray);
// 字符串引用比较
System.out.println(str0 == str1); // true
System.out.println(str0 == str3); // false
System.out.println(str0.equals(str3)); // true
// 字符串比较
String str5 = null;
System.out.println("abc".equals(str5)); // 推荐
System.out.println(str5.equals("abc")); // NullPointerException
String strA = "JAva";
String strB = "java";
System.out.println(strA.equalsIgnoreCase(strB)); //忽略大小写
}
}
成员方法
类型 | 方法 | 说明 |
---|---|---|
获取 | ||
char | charAt(int index) | 返回指定索引处的 char 值 |
int | indexOf(int ch) | 返回指定字符在此字符串中第一次出现处的索引 |
boolean | contains(CharSequence s) | 当且仅当此字符串包含指定的 char 值序列时,返回 true |
boolean | endsWith(String suffix) | 测试此字符串是否以指定的后缀结束 |
boolean | startsWith(String prefix) | 测试此字符串是否以指定的前缀开始 |
boolean | matches(String regex) | 告知此字符串是否匹配给定的正则表达式 |
int | length() | 返回此字符串的长度 |
boolean | isEmpty() | length() 为 0 时返回 true |
boolean | equalsIgnoreCase(String anotherString) | 将此 String 与另一个 String 比较,不考虑大小写 |
操作 | ||
String | concat(String str) | 尾插法连接字符串 |
byte[] | getBytes() | 使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中 |
String[] | split(String regex) | 根据给定正则表达式的匹配拆分此字符串 |
String | substring(int beginIndex, int endIndex) | 返回一个新的字符串,它是此字符串的一个子字符串 |
String | toLowerCase() | 使用默认语言环境的规则将此 String 中的所有字符都转换为小写 |
String | toUpperCase() | 使用默认语言环境的规则将此 String 中的所有字符都转换为大写 |
String | trim() | 返回字符串的副本,忽略前导空白和尾部空白 |
int | compareTo(String anotherString) | 按字典顺序比较两个字符串 |
boolean | equals(Object anObject) | 将此字符串与指定的对象比较 |
int | hashCode() | 返回此字符串的哈希码 |
char[] | toCharArray() | 将此字符串转换为一个新的字符数组 |
String | toString() | 返回此对象本身 |
static String | valueOf(T t) | 返回 T 参数的字符串表示形式 |
String Q&A
String 和 int 转换
- String 转 int:Integer.valueOf("str")、Integer.PaseInt(str)
- int 转 String:String.valueOf(12)、12 + ""
equals和==
- ==:
- 基本数据类型变量,比较其存储的值是否相等
- 引用类型变量,比较所指向的对象地址(即是否指向同一个对象)
- equals:比较指向对象的内容是否相同,不能作用于基本数据类型的变量
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
String相关的+
String 中使用 + 字符串连接符进行字符串连接时,连接操作最开始时如果都是字符串常量,编译后将尽可能多的直接将字符串常量连接起来,形成新的字符串常量参与后续连接。接下来的字符串连接是从左向右依次进行,对于不同的字符串,首先以最左边的字符串为参数创建 StringBuilder 对象,然后依次对右边进行 append操作,最后将 StringBuilder 对象通过 toString() 方法转换成 String 对象(注意:中间的多个字符串常量不会自动拼接)
String c = "xx" + "yy " + a + "zz" + "mm" + b;
实现过程:
String c = new StringBuilder("xxyy ").append(a).append("zz").append("mm").append(b).toString();
当使用+进行多个字符串连接时,实际上是产生了一个StringBuilder对象和一个String对象
StringBuffer
StringBuffer特点
- 字符串的缓冲区(缓冲区可变长度),是一个容器,和 String 类不同的是,StringBuffer 类的对象能够被多次的修改,并且不产生新的未使用对象
StringBuffer源码
构造方法
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/**
* 构造一个空的 StringBuffer 对象,初始容量为16个字符
* @return StringBuffer对象
*/
public StringBuffer() {
super(16);
// bstractStringBuilder(int capacity) { value = new char[capacity]; }
}
/**
* 构造一个空的 StringBuffer 对象,初始容量为 capacity
* @param capacity 初始容量
* @return StringBuffer对象
*/
public StringBuffer(int capacity) {
super(capacity);
}
/**
* 构造一个空的 StringBuffer 对象,初始容量为 str.length() + 16
* @param str [description]
* @return StringBuffer对象
*/
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
/**
* 构造一个包含与指定的 CharSequence 相同字符的空 StringBuffer 对象,初始容量为 seq.length() + 16
* @param seq [description]
* @return StringBuffer对象
*/
public StringBuffer(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
}
成员方法
类型 | 方法 | 说明 |
---|---|---|
StringBuffer | append(T t) | 添加各种类型的数据 |
StringBuffer | insert(int offset, T t) | 在容器指定位置插入各种类型的数据 |
StringBuffer | deleteCharAt(int index) | 删除指定位置的字符 |
StringBuffer | delete(int start, int end) | 移除此序列的子字符串中的字符 |
StringBuffer | replace(int start, int end, String str) | 替换 |
char | charAt(int index) | 获取指定索引处的 char 值 |
int | length() | 元素个数 |
int | capacity() | 当前容量 |
int | indexOf(String str) | 返回第一次出现指定子字符串在该字符串的索引 |
int | lastIndexOf(String str) | 返回最右边出现指定子字符串在此字符串的索引 |
String | substring(int start) | 截取 |
String | substring(int start, int end) | 返回包含此字符序列当前所包含字符子序列 |
StringBuffer | reverse() | 反转 |
String | toString() | 返回此序列中数据的字符串表示形式 |
StringBuilder
StringBuilder特点
StringBuilder源码
构造方法
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
/**
* 构造一个不带任何字符的 StringBuilder 对象,其初始容量为 16 个字符
* @return StringBuilder对象
*/
public StringBuilder() {
super(16);
}
/**
* 构造一个不带任何字符的 StringBuilder 对象,其初始容量由 capacity 参数指定
* @param capacity 初始容量
* @return StringBuilder对象
*/
public StringBuilder(int capacity) {
super(capacity);
}
/**
* 构造一个 StringBuilder 对象,并初始化为指定的字符串内容,初始容量为 str.length() + 16
* @param str 指定的字符串内容
* @return StringBuilder对象
*/
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
/**
* 构造一个 StringBuilder 对象,包含与指定的 CharSequence 相同的字符,初始容量为 seq.length() + 16
* @param seq CharSequence字符
* @return StringBuilder对象
*/
public StringBuilder(CharSequence seq) {
this(seq.length() + 16);
append(seq);
}
}
成员方法
类型 | 方法 | 说明 |
---|---|---|
StringBuilder | append(T t) | 添加各种类型的数据 |
StringBuilder | insert(int offset, T t) | 在容器指定位置插入各种类型的数据 |
StringBuilder | deleteCharAt(int index) | 删除指定位置的字符 |
StringBuilder | delete(int start, int end) | 移除此序列的子字符串中的字符 |
StringBuilder | replace(int start, int end, String str) | 替换 |
char | charAt(int index) | 获取指定索引处的 char 值 |
int | length() | 元素个数 |
int | capacity() | 当前容量 |
int | indexOf(String str) | 返回第一次出现的指定子字符串在该字符串的索引 |
int | lastIndexOf(String str) | 返回最右边出现的指定子字符串在此字符串的索引 |
String | substring(int start) | 截取 |
String | substring(int start, int end) | 返回包含此字符序列当前所包含的字符子序列 |
StringBuilder | reverse() | 反转 |
String | toString() | 返回此序列中数据的字符串表示形式 |