前言
String 类为字符串,是Java总常用类之一。
public final class String{...}
String 类被final修饰:表示该类不能被继承、其中所有方法隐式的被final修饰不能被重写。
注:String为不可派生类,因此也就不会产生重写。
String 类包括的方法可用于检查序列的单个字符、比较字符串、搜索字符串、提取子字符串、创建字符串副本并将所有字符全部转换为大写或小写。
字段
private final char value[];//存储字符数组
注:
- 通过此变量可以看出String是基于char数组实现。
- 变量value被final修饰,标识变量不可变,这也正是字符串不可变的原因。
private int hash;//缓存的当前字符串的哈希值
注:
- 变量hash为int类型,默认值为0
构造方法
无参构造
- 创建并初始化一个String对象,当前对象表示的是与字符数组(长度为0)相同的字符序列。
因为变量value为不可变的,使用此构造方法创建字符串没有意义。
public String() {
//创建一个char数组长度为0,赋值给当前对象的变量value。
this.value = new char[0];
}
有参构造
- 创建并初始化一个String对象,当前对象表示的是与参数列表(String对象)相同的字符序列。
public String(String original) {
//将参数列表的字符序列赋值给当前对象的变量value
this.value = original.value;
this.hash = original.hash;
}
- 创建并初始化一个String对象,当前对象表示的是与参数列表(字符数组)的副本相同的字符序列
注:Arrays.copyOf
在java.Util包下第一个参数为要复制的对象,第二个参数为返回的副本长度
public String(char value[]) {
//将参数字符数组副本赋值给当前对象的变量value
this.value = Arrays.copyOf(value, value.length);
}
- 创建并初始化一个String对象,当前对象表示的是与参数列表(字符数组)的副本(副本需指定长度)相同的字符序列
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
//将参数字符列表指定长度(从offset到offset+count(含头不含尾))
//副本赋值给当前对象的变量value
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
- 创建并初始化一个String对象,它包含 Unicode 代码点数组的参数其中的一个子数组的字符。offset 参数是该子数组第一个代码点的索引,count 参数是指定子数组的长度。将该子数组的内容转换为 char;后续对 int 数组的修改不会影响新创建的字符串。
备注:由于对字符集不熟悉其中有两处有问题待研究
public String(int[] codePoints, int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
// Note: offset or count might be near -1>>>1.
if (offset > codePoints.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
final int end = offset + count;
//确定变量v的数组长度
int n = count;
for (int i = offset; i < end; i++) {
int c = codePoints[i];
//判断所截取子串的值是否在0-65536范围之间
if (Character.isBmpCodePoint(c)){
continue;
//如果不在0-65535之间
//字符集不熟悉待研究
}else if (Character.isValidCodePoint(c)){
n++;
}else{ throw new IllegalArgumentException(Integer.toString(c));
}
}
//向数组中添加数据
final char[] v = new char[n];
for (int i = offset, j = 0; i < end; i++, j++) {
int c = codePoints[i];
//判断所截取子串的值是否在0-65536范围之间
if (Character.isBmpCodePoint(c)){
//转化成char添加到变量v数组
v[j] = (char)c;
}else{
//如果不在0-65535之间
//字符集不熟悉待研究
Character.toSurrogates(c, v, j++);
}
}
//将字符数组赋值给当前对象变量value
this.value = v;
}
以下构造方法开发中不常用
- 用于检查字节数组的通用私有工具方法
private static void checkBounds(byte[] bytes, int offset, int length) {
if (length < 0)
throw new StringIndexOutOfBoundsException(length);
if (offset < 0)
throw new StringIndexOutOfBoundsException(offset);
if (offset > bytes.length - length)
throw new StringIndexOutOfBoundsException(offset + length);
}
- 通过使用指定的字符集解码指定的 byte 子数组,构造一个新的 String。
当字符集charsetName不指定时,此构造方法无作用。
bytes - 要解码为字符的 byte
offset - 要解码的第一个 byte 的索引
length - 要解码的 byte 数
charsetName - 受支持 charset 的名称
StringCoding
未阅读
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);
}
- 调用上一个构造方法
offset - 要解码的第一个 byte 的索引(默认从0)
length - 要解码的 byte 数(数组长度)
public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException {
this(bytes, 0, bytes.length, charsetName);
}
- 通过使用指定的 charset 解码指定的 byte 子数组,构造一个新的 String。此方法总是使用此字符集的默认替代字符串替代错误输入和不可映射字符序列。
bytes - 要解码为字符的 byte
offset - 要解码的第一个 byte 的索引
length - 要解码的 byte 数
charset - 用来解码 bytes 的 charset StringCoding
未阅读
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);
}
- 调用上一个构造函数
区别:上一个构造方法可以指定(本构造方法自己指定)
offset - 要解码的第一个 byte 的索引(默认从0)
length - 要解码的 byte 数(数组长度)
public String(byte bytes[], Charset charset) {
this(bytes, 0, bytes.length, charset);
}
- 通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。新 String 的长度是字符集的函数,因此可能不等于该子数组的长度。
当给定 byte 在给定字符集中无效的情况下,此构造方法的行为没有指定。
bytes - 要解码为字符的 byte
offset - 要解码的第一个 byte 的索引
length - 要解码的 byte 数
注:调用ISO-8859-1字符集
- StringCoding
未阅读
public String(byte bytes[], int offset, int length) {
//调用检查字节数组的通用私有工具方法,检查有效性
checkBounds(bytes, offset, length);
this.value = StringCoding.decode(bytes, offset, length);
}
- 调用上一个构造方法
区别:上一个构造方法可以指定(本构造方法自己指定)
offset - 要解码的第一个 byte 的索引(默认从0)
length - 要解码的 byte 数(数组长度)
public String(byte bytes[]) {
this(bytes, 0, bytes.length);
}
- 分配一个新的字符串,它包含字符串缓冲区参数中当前包含的字符序列。该字符串缓冲区的内容已被复制,后续对它的修改不会影响新创建的字符串。
public String(StringBuffer buffer) {
//同步锁,线程安全
synchronized(buffer) {
this.value = Arrays.copyOf(buffer.getValue(), buffer.length());
}
}
- 分配一个新的字符串,它包含字符串生成器参数中当前包含的字符序列。该字符串生成器的内容已被复制,后续对它的修改不会影响新创建的字符串。
public String(StringBuilder builder) {
this.value = Arrays.copyOf(builder.getValue(), builder.length());
}
java源码阅读-java.lang.String(02)
如有语言和理解上的错误请大家指出,积极讨论,本人及时修改。