String 部分源码分析
String
- 无参数构造函数
/**
* 底层存储字符串的目标字节数组,
* Jdk 8 之前都是字符数组 private final char[] value;
*/
@Stable
private final byte[] value;
/**
* 编码底层字节数组的字符集,支持 LATIN1、UTF16
*/
private final byte coder;
/**
* 字符串的哈希码值,默认为 0
*/
private int hash; // Default to 0
/**
* 创建一个空字符串
* created by ZXD at 18 Nov 2018 T 11:17:48
*/
public String() {
this.value = "".value;
this.coder = "".coder;
}
- 基于字节数组创建字符串
public String(byte[] bytes) {
this(bytes, 0, bytes.length);
}
public String(byte bytes[], int offset, int length) {
checkBoundsOffCount(offset, length, bytes.length);
// 对目标字节数组进行编码
StringCoding.Result ret = StringCoding.decode(bytes, offset, length);
// 获取编码后的字节数组
this.value = ret.value;
// 获取编码后的字符集
this.coder = ret.coder;
}
public String(byte bytes[], Charset charset) {
this(bytes, 0, bytes.length, charset);
}
public String(byte bytes[], int offset, int length, Charset charset) {
// 防御式编程,null 校验
if (charset == null)
throw new NullPointerException("charset");
checkBoundsOffCount(offset, length, bytes.length);
// 根据指定的字符集对字节数组进行编码
StringCoding.Result ret =
StringCoding.decode(charset, bytes, offset, length);
this.value = ret.value;
this.coder = ret.coder;
}
public String(byte bytes[], String charsetName)
throws UnsupportedEncodingException {
this(bytes, 0, bytes.length, charsetName);
}
public String(byte bytes[], int offset, int length, String charsetName)
throws UnsupportedEncodingException {
if (charsetName == null)
throw new NullPointerException("charsetName");
checkBoundsOffCount(offset, length, bytes.length);
// 根据指定的字符集对字节数组进行编码,编码名称错误时,抛出 UnsupportedEncodingException 异常
StringCoding.Result ret =
StringCoding.decode(charsetName, bytes, offset, length);
this.value = ret.value;
this.coder = ret.coder;
}
- 基于字符数组创建字符串
public String(char value[]) {
this(value, 0, value.length, null);
}
public String(char value[], int offset, int count) {
this(value, offset, count, rangeCheck(value, offset, count));
}
private static Void rangeCheck(char[] value, int offset, int count) {
// 字符串下标合法性校验
checkBoundsOffCount(offset, count, value.length);
return null;
}
String(char[] value, int off, int len, Void sig) {
// 特殊场景优化处理
if (len == 0) {
this.value = "".value;
this.coder = "".coder;
return;
}
if (COMPACT_STRINGS) {
// 如果启用压缩,则将字符数组压缩,字符集设置为 LATIN1
byte[] val = StringUTF16.compress(value, off, len);
if (val != null) {
this.value = val;
this.coder = LATIN1;
return;
}
}
// 字符数组不压缩时,字符集设置为 UTF16
this.coder = UTF16;
this.value = StringUTF16.toBytes(value, off, len);
}
- 字符串内容相等性比较
public boolean equals(Object anObject) {
// 地址相等则直接返回 true
if (this == anObject) {
return true;
}
// 形参对象为字符串
if (anObject instanceof String) {
String aString = (String)anObject;
// 字符编码相同时才能做比较
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
- 字符串的长度
public int length() {
return value.length >> coder();
}
byte coder() {
return COMPACT_STRINGS ? coder : UTF16;
}
@Native static final byte LATIN1 = 0;
@Native static final byte UTF16 = 1; // Unicode字符集的抽象码位映射为16位长的整数
- 比较字符串内容并且不区分大小写
public boolean equalsIgnoreCase(String anotherString) {
return (this == anotherString) ? true
: (anotherString != null) // 形参字符串不为 null
&& (anotherString.length() == length()) // 两个字符串长度一致
&& regionMatches(true, 0, anotherString, 0, length()); // 编码后的区域是否匹配
}
- 字符串拼接
public String concat(String str) {
int olen = str.length();
if (olen == 0) {
return this;
}
// 字符集相同时,直接通过数组拷贝进行拼接
if (coder() == str.coder()) {
byte[] val = this.value;
byte[] oval = str.value;
int len = val.length + oval.length;
byte[] buf = Arrays.copyOf(val, len);
System.arraycopy(oval, 0, buf, val.length, oval.length);
return new String(buf, coder);
}
int len = length();
// 使用 UTF16 编码计算目标字节数组长度,并将它们都拷贝进去。
byte[] buf = StringUTF16.newBytesFor(len + olen);
getBytes(buf, 0, UTF16);
str.getBytes(buf, len, UTF16);
return new String(buf, UTF16);
}
- 字符串截取
public String substring(int beginIndex, int endIndex) {
int length = length();
// 索引合法性检测
checkBoundsBeginEnd(beginIndex, endIndex, length);
int subLen = endIndex - beginIndex;
// 特殊场景优化处理,截取的子字符串就是目标字符串
if (beginIndex == 0 && endIndex == length) {
return this;
}
return isLatin1() ? StringLatin1.newString(value, beginIndex, subLen)
: StringUTF16.newString(value, beginIndex, subLen);
}
/**
* 起始索引和结束索引不在 0到 length()-1 范围内,则抛出 IndexOutOfBoundsException 异常
* 结束索引大于起始索引,则抛出 IndexOutOfBoundsException 异常
*/
static void checkBoundsBeginEnd(int begin, int end, int length) {
if (begin < 0 || begin > end || end > length) {
throw new StringIndexOutOfBoundsException(
"begin " + begin + ", end " + end + ", length " + length);
}
}
- 获取字符串中指定索引处的单个字符
public char charAt(int index) {
if (isLatin1()) {
return StringLatin1.charAt(value, index);
} else {
return StringUTF16.charAt(value, index);
}
}
StringLatin1#charAt
public static char charAt(byte[] value, int index) {
if (index < 0 || index >= value.length) {
throw new StringIndexOutOfBoundsException(index);
}
return (char)(value[index] & 0xff);
}
- 目标字符串是否包含子字符串
public boolean contains(CharSequence s) {
return indexOf(s.toString()) >= 0;
}
- 字符串是否为空
public boolean isEmpty() {
return value.length == 0;
}
- 字符串替换
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
String ret = isLatin1() ? StringLatin1.replace(value, oldChar, newChar)
: StringUTF16.replace(value, oldChar, newChar);
if (ret != null) {
return ret;
}
}
return this;
}
public String replace(CharSequence target, CharSequence replacement) {
// 需要查找的字符序列
String tgtStr = target.toString();
// 需要替换的字符序列
String replStr = replacement.toString();
// 如果要查找的字符序列没有在目标字符串中,则返回其本身
int j = indexOf(tgtStr);
if (j < 0) {
return this;
}
// 查找字符序列的长度
int tgtLen = tgtStr.length();
int tgtLen1 = Math.max(tgtLen, 1);
// 当期字符串的长度
int thisLen = length();
int newLenHint = thisLen - tgtLen + replStr.length();
if (newLenHint < 0) {
throw new OutOfMemoryError();
}
StringBuilder sb = new StringBuilder(newLenHint);
int i = 0;
// 在 StringBuilder 指定的索引处追加字符串,并重新获取要查找的子字符串索引进行循环替换。
do {
sb.append(this, i, j).append(replStr);
i = j + tgtLen;
} while (j < thisLen && (j = indexOf(tgtStr, j + tgtLen1)) > 0);
return sb.append(this, i, thisLen).toString();
}
- 基于正则表达式替换字符串
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
- 基于正则表达式替换首次出现的字符串
public String replaceFirst(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}
String 部分源码分析的更多相关文章
- String 类源码分析
String 源码分析 String 类代表字符序列,Java 中所有的字符串字面量都作为此类的实例. String 对象是不可变的,它们的值在创建之后就不能改变,因此 String 是线程安全的. ...
- python string.py 源码分析 三:maketrans
l = map(chr, xrange(256)) #将ascii转为字符串 _idmap = str('').join(l) del l # Construct a translation stri ...
- String类源码分析(JDK1.7)
以下学习根据JDK1.7String类源代码做注释 public final class String implements java.io.Serializable, Comparable<S ...
- python string.py 源码分析 二:capwords
def capwords(s, sep=None): """capwords(s [,sep]) -> string Split the argument into ...
- String类源码分析
1.String类注释说明 /** * The {@code String} class represents character strings. All * string literals in ...
- python string.py 源码分析 一
# Some strings for ctype-style character classification c风格字符串 whitespace = ' \t\n\r\v\f' #空白字符 \t 制 ...
- 【源码分析】你必须知道的string.IsNullOrEmpty && string.IsNullOrWhiteSpace
写在前面 之前自信撸码时踩了一次小坑,代码如下: private static void AppServer_NewMessageReceived(WebSocketSession session, ...
- Java源码分析:关于 HashMap 1.8 的重大更新(转载)
http://blog.csdn.net/carson_ho/article/details/79373134 前言 HashMap 在 Java 和 Android 开发中非常常见 而HashMap ...
- [源码]String StringBuffer StringBudlider(2)StringBuffer StringBuilder源码分析
纵骑横飞 章仕烜 昨天比较忙 今天把StringBuffer StringBulider的源码分析 献上 在讲 StringBuffer StringBuilder 之前 ,我们先看一下 ...
随机推荐
- Xshell6,亲测可用~破解版简单解压免安装~已更新官方版本安装方法
下面的内容别看了,使用这个最新的安装官方版本 https://www.cnblogs.com/taopanfeng/p/11671727.html 下面的内容别看了,使用这个最新的安装官方版本 htt ...
- ipc - System V 进程间通信机制
SYNOPSIS 总览 # include <sys/types.h> # include <sys/ipc.h> # include <sys/msg.h> # ...
- 34.ITerm配置使用——2019年12月24日
2019年12月23日15:17:36 ITerm使用教程 1.快键键配置 设置方法 设置方法如下: (1)选择 Preference 进入偏好设置: (2)选择 Profiles > Keys ...
- hive中的null
在处理流水增量表的时候,出现了一个判定的失误. select a.a1,a.a2 from ( select a.a1 ,,) as diff ,a.a2 from a lefter join b o ...
- win10激活方法 windows 10 最简单的激活方法
1.首先,要用管理员权限打开cmd命令行窗口,可以搜索框中输入“cmd”,在出现的“命令行提示符”,图标上右击“以管理员身份运行”. 2.为了让其它激活工具的密钥清除,先卸载密钥,在命令行输入 ...
- Linux缺少动态连接库.so--cannot open shared object file: No such file or directory
1 Liunx安装报错时,缺少动态链接库时,形式如下: /usr/local/libexec/gcc/x86_64-unknown-liunx-gnu/4.8.2/cc1: error while l ...
- 目标检测 | OHEM
参考:https://blog.csdn.net/app_12062011/article/details/77945600 参考:http://www.cnblogs.com/sddai/p/102 ...
- ClustrixDB安装配置
前提条件 在安装ClustrixDB之前,需要: ClustrixDB安装程序和许可证密钥. 运行CentOS或RHEL 7.4的服务器(本地或云中). 具有root或sudo特权来安装Clustri ...
- Linux设置程序开机自启动
注意: 作者测试时,Linux版本为RedHat6,同时应用在CentOS6应该也可以(作者未实测,但有同事在CentOS6上使用可行),系统版本的不同,可能造成操作上的差异(CentOS7就与Cen ...
- luogu P1141 01迷宫 x
P1141 01迷宫 题目描述 有一个仅由数字0与1组成的n×n格迷宫.若你位于一格0上,那么你可以移动到相邻4格中的某一格1上,同样若你位于一格1上,那么你可以移动到相邻4格中的某一格0上. 你的任 ...