java源码解析之String类(五)
/*
* 切片函数,非常重要,这里一定要牢记beginIndex是开始位置,endIndex是结束位置,区别于以前学的offset是开始位置,而count或length是个数和长度
* 比如说,new String("abcdefg",1,3)得到的是bcd
* 而 "abcdefg".substring(1,3)得到的是bc,也就是下标为1和2的俩个字符,并不包括c
*/
public String substring(int beginIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
int subLen = value.length - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
}
public String substring(int beginIndex, int endIndex) {
if (beginIndex < 0) {
throw new StringIndexOutOfBoundsException(beginIndex);
}
if (endIndex > value.length) {
throw new StringIndexOutOfBoundsException(endIndex);
}
int subLen = endIndex - beginIndex;
if (subLen < 0) {
throw new StringIndexOutOfBoundsException(subLen);
}
return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen);
} /*
* 返回的是一个字符序列CharSequence,而CharSequence是一个接口,所有这里需要的是CharSequence的实现类
* 而String实现的最后一个接口就是CharSequence,所以其实这里返回的就是String对象
* 但是这是一个多态对象,他能调用的方法只有CharSequence接口中的几个,所以此方法没用,除非程序就需要一个CharSequence对象
*
*/
public CharSequence subSequence(int beginIndex, int endIndex) {
return this.substring(beginIndex, endIndex);
} /*
* 将指定的字符串连接到该字符串的末尾。 如果参数字符串的长度为0 ,则返回此String对象。
* 这里使用了new String(buf, true)
* 否则,返回一个String对象,表示一个字符序列,该字符序列是由该String对象表示的字符序列与由参数字符串表示的字符序列的级联。
* 如果需要大量的字符串拼接,请使用StringBuffer和StringBuilder
*/
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
} /*
* 判断此字符串是否匹配指定的regaex正则表达式,正则表达式有些复杂,需要一章来叙述,这里不做赘述
*/
public boolean matches(String regex) {
return Pattern.matches(regex, this);
} /*
* 判断此字符串是否包含指定的字符序列CharSequence,CharSequence在上面已经讲过了
*/
public boolean contains(CharSequence s) {
return indexOf(s.toString()) > -1;
}
/*
* 替换字符串中的某个字符,注意参数都是字符char类型
* 例如:"gollong".replace("o","")的结果为"gllng"
*/
public String replace(char oldChar, char newChar) {
if (oldChar != newChar) {
int len = value.length;
int i = -1;
char[] val = value; /* avoid getfield opcode */ while (++i < len) {
if (val[i] == oldChar) {
break;
}
}
if (i < len) {
char buf[] = new char[len];
for (int j = 0; j < i; j++) {
buf[j] = val[j];
}
while (i < len) {
char c = val[i];
buf[i] = (c == oldChar) ? newChar : c;
i++;
}
return new String(buf, true);
}
}
return this;
} /*
* 替换字符串中的字字符串,识别方式为正则表达式
* replaceFirst只替换第一个
* replaceAll为全部替换
*/
public String replaceFirst(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceFirst(replacement);
}
public String replaceAll(String regex, String replacement) {
return Pattern.compile(regex).matcher(this).replaceAll(replacement);
}
public String replace(CharSequence target, CharSequence replacement) {
return Pattern.compile(target.toString(), Pattern.LITERAL).matcher(this)
.replaceAll(Matcher.quoteReplacement(replacement.toString()));
} /*
* 切割字符串,形参regex是一个正则表达式。limit用于限制String[]的长度
* 例如,字符串"boo:and:foo"使用以下参数产生以下结果:
* Regex Limit Result
* : 2 { "boo", "and:foo" }
* : 5 { "boo", "and", "foo" }
* : -2 { "boo", "and", "foo" }
* o 5 { "b", "", ":and:f", "", "" }
* o -2 { "b", "", ":and:f", "", "" }
* o 0 { "b", "", ":and:f" } */
public String[] split(String regex, int limit) {
char ch = 0;
if (((regex.value.length == 1 && ".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1)
|| (regex.length() == 2 && regex.charAt(0) == '\\' && (((ch = regex.charAt(1)) - '0') | ('9' - ch)) < 0
&& ((ch - 'a') | ('z' - ch)) < 0 && ((ch - 'A') | ('Z' - ch)) < 0))
&& (ch < Character.MIN_HIGH_SURROGATE || ch > Character.MAX_LOW_SURROGATE)) {
int off = 0;
int next = 0;
boolean limited = limit > 0;
ArrayList<String> list = new ArrayList<>();
while ((next = indexOf(ch, off)) != -1) {
if (!limited || list.size() < limit - 1) {
list.add(substring(off, next));
off = next + 1;
} else { // last one
// assert (list.size() == limit - 1);
list.add(substring(off, value.length));
off = value.length;
break;
}
}
// If no match was found, return this
if (off == 0)
return new String[] { this }; // Add remaining segment
if (!limited || list.size() < limit)
list.add(substring(off, value.length)); // Construct result
int resultSize = list.size();
if (limit == 0) {
while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {
resultSize--;
}
}
String[] result = new String[resultSize];
return list.subList(0, resultSize).toArray(result);
}
return Pattern.compile(regex).split(this, limit);
} public String[] split(String regex) {
return split(regex, 0);
} /*
* 去掉字符串两端的空格,很有用的小方法
*/
public String trim() {
int len = value.length;
int st = 0;
char[] val = value; /* avoid getfield opcode */ while ((st < len) && (val[st] <= ' ')) {
st++;
}
while ((st < len) && (val[len - 1] <= ' ')) {
len--;
}
return ((st > 0) || (len < value.length)) ? substring(st, len) : this;
} /*
* toString返回这个对象本身,
* 重点:我们总以为直接输出一个字符串对象可以打印其char数组的内容是因为String重写了toString方法
* 我们认为System.out.println(str)就是System.out.println(str.toString())
* 其实不是的,我们很清楚的看到了,toString方法就是返回一个String对象,并不是遍历
* 于是乎我们得到了一个结论:
* System.out.println(str.toString())就是System.out.println(str)他们都依赖于String的特殊的实现机制
* 这个机制就是:String s = "gollopng"就是创造对象并实例化
* System.out.println(str)就是直接遍历输出
*/
public String toString() {
return this;
} /*
* 将字符串转换为char数组,此时联想一下charAt方法,不要记混了
*/
public char[] toCharArray() {
// Cannot use Arrays.copyOf because of class initialization order issues
char result[] = new char[value.length];
System.arraycopy(value, 0, result, 0, value.length);
return result;
} /*
* 返回字符串对象的规范表示,它遵循以下规则:对于任意两个字符串 s 和 t,当且仅当 s.equals(t) 为 true 时,s.intern() == t.intern() 才为 true。
* 尽管在输出中调用intern方法并没有什么效果,但是实际上后台这个方法会做一系列的动作和操作。在调用”gollong”.intern()方法的时候会返回”gollong”,
* 但是这个方法会首先检查字符串常量池中是否有”gollong”这个字符串,如果存在则该引用指向它,否则就将这个字符添加到字符串池中,然会再指向。
*/
public native String intern(); /*
* 返回一个新的字符串,由 CharSequence elements的副本组成,并附有指定的delimiter的 delimiter
*/
public static String join(CharSequence delimiter, CharSequence... elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
// Number of elements not likely worth Arrays.stream overhead.
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs : elements) {
joiner.add(cs);
}
return joiner.toString();
} /*
* 返回一个新 String的副本组成 CharSequence elements与指定的副本一起加入 delimiter 。
*/
public static String join(CharSequence delimiter, Iterable<? extends CharSequence> elements) {
Objects.requireNonNull(delimiter);
Objects.requireNonNull(elements);
StringJoiner joiner = new StringJoiner(delimiter);
for (CharSequence cs : elements) {
joiner.add(cs);
}
return joiner.toString();
} /*
* toLowerCase(Locale locale):将字符串中所有小写字符转换为大写,其中locale用于指定自己的规则
* toUpperCase(Locale locale):将字符串中所有大写字符转换为小写,其中locale用于指定自己的规则
*/
public String toLowerCase(Locale locale) {
if (locale == null) {
throw new NullPointerException();
} int firstUpper;
final int len = value.length; /* Now check if there are any characters that need to be changed. */
scan: {
for (firstUpper = 0; firstUpper < len;) {
char c = value[firstUpper];
if ((c >= Character.MIN_HIGH_SURROGATE) && (c <= Character.MAX_HIGH_SURROGATE)) {
int supplChar = codePointAt(firstUpper);
if (supplChar != Character.toLowerCase(supplChar)) {
break scan;
}
firstUpper += Character.charCount(supplChar);
} else {
if (c != Character.toLowerCase(c)) {
break scan;
}
firstUpper++;
}
}
return this;
} char[] result = new char[len];
int resultOffset = 0;
System.arraycopy(value, 0, result, 0, firstUpper); String lang = locale.getLanguage();
boolean localeDependent = (lang == "tr" || lang == "az" || lang == "lt");
char[] lowerCharArray;
int lowerChar;
int srcChar;
int srcCount;
for (int i = firstUpper; i < len; i += srcCount) {
srcChar = (int) value[i];
if ((char) srcChar >= Character.MIN_HIGH_SURROGATE && (char) srcChar <= Character.MAX_HIGH_SURROGATE) {
srcChar = codePointAt(i);
srcCount = Character.charCount(srcChar);
} else {
srcCount = 1;
}
if (localeDependent || srcChar == '\u03A3' || // GREEK CAPITAL LETTER SIGMA
srcChar == '\u0130') { // LATIN CAPITAL LETTER I WITH DOT ABOVE
lowerChar = ConditionalSpecialCasing.toLowerCaseEx(this, i, locale);
} else {
lowerChar = Character.toLowerCase(srcChar);
}
if ((lowerChar == Character.ERROR) || (lowerChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
if (lowerChar == Character.ERROR) {
lowerCharArray = ConditionalSpecialCasing.toLowerCaseCharArray(this, i, locale);
} else if (srcCount == 2) {
resultOffset += Character.toChars(lowerChar, result, i + resultOffset) - srcCount;
continue;
} else {
lowerCharArray = Character.toChars(lowerChar);
} /* Grow result if needed */
int mapLen = lowerCharArray.length;
if (mapLen > srcCount) {
char[] result2 = new char[result.length + mapLen - srcCount];
System.arraycopy(result, 0, result2, 0, i + resultOffset);
result = result2;
}
for (int x = 0; x < mapLen; ++x) {
result[i + resultOffset + x] = lowerCharArray[x];
}
resultOffset += (mapLen - srcCount);
} else {
result[i + resultOffset] = (char) lowerChar;
}
}
return new String(result, 0, len + resultOffset);
}
public String toLowerCase() {
return toLowerCase(Locale.getDefault());
}
public String toUpperCase(Locale locale) {
if (locale == null) {
throw new NullPointerException();
}
int firstLower;
final int len = value.length;
scan: {
for (firstLower = 0; firstLower < len;) {
int c = (int) value[firstLower];
int srcCount;
if ((c >= Character.MIN_HIGH_SURROGATE) && (c <= Character.MAX_HIGH_SURROGATE)) {
c = codePointAt(firstLower);
srcCount = Character.charCount(c);
} else {
srcCount = 1;
}
int upperCaseChar = Character.toUpperCaseEx(c);
if ((upperCaseChar == Character.ERROR) || (c != upperCaseChar)) {
break scan;
}
firstLower += srcCount;
}
return this;
}
int resultOffset = 0;
char[] result = new char[len];
System.arraycopy(value, 0, result, 0, firstLower); String lang = locale.getLanguage();
boolean localeDependent = (lang == "tr" || lang == "az" || lang == "lt");
char[] upperCharArray;
int upperChar;
int srcChar;
int srcCount;
for (int i = firstLower; i < len; i += srcCount) {
srcChar = (int) value[i];
if ((char) srcChar >= Character.MIN_HIGH_SURROGATE && (char) srcChar <= Character.MAX_HIGH_SURROGATE) {
srcChar = codePointAt(i);
srcCount = Character.charCount(srcChar);
} else {
srcCount = 1;
}
if (localeDependent) {
upperChar = ConditionalSpecialCasing.toUpperCaseEx(this, i, locale);
} else {
upperChar = Character.toUpperCaseEx(srcChar);
}
if ((upperChar == Character.ERROR) || (upperChar >= Character.MIN_SUPPLEMENTARY_CODE_POINT)) {
if (upperChar == Character.ERROR) {
if (localeDependent) {
upperCharArray = ConditionalSpecialCasing.toUpperCaseCharArray(this, i, locale);
} else {
upperCharArray = Character.toUpperCaseCharArray(srcChar);
}
} else if (srcCount == 2) {
resultOffset += Character.toChars(upperChar, result, i + resultOffset) - srcCount;
continue;
} else {
upperCharArray = Character.toChars(upperChar);
}
int mapLen = upperCharArray.length;
if (mapLen > srcCount) {
char[] result2 = new char[result.length + mapLen - srcCount];
System.arraycopy(result, 0, result2, 0, i + resultOffset);
result = result2;
}
for (int x = 0; x < mapLen; ++x) {
result[i + resultOffset + x] = upperCharArray[x];
}
resultOffset += (mapLen - srcCount);
} else {
result[i + resultOffset] = (char) upperChar;
}
}
return new String(result, 0, len + resultOffset);
} public String toUpperCase() {
return toUpperCase(Locale.getDefault());
} /*
* 使用指定的格式字符串和参数返回格式化的字符串。 Object... args是可变参数
*/
public static String format(String format, Object... args) {
return new Formatter().format(format, args).toString();
} /*
* 使用指定的区域设置,格式字符串和参数返回格式化的字符串。
*/
public static String format(Locale l, String format, Object... args) {
return new Formatter(l).format(format, args).toString();
} /*
* 下面是String通过静态方法将其他类型转换为字符串
* 总结:将其他类型转换为字符串有三种方法
* 1.String的构造器:可以转换byte[]、char[]、int[]
* 2.String的静态方法valueOf:可以转换Object对象、char[]、boolean、char、int、long、float、double
* 3.其他类型的toString方法:只要是重写了toString,就可以转换
*/
public static String valueOf(Object obj) {
return (obj == null) ? "null" : obj.toString();
}
public static String valueOf(char data[]) {
return new String(data);
}
public static String valueOf(char data[], int offset, int count) {
return new String(data, offset, count);
} public static String copyValueOf(char data[], int offset, int count) {
return new String(data, offset, count);
} public static String copyValueOf(char data[]) {
return new String(data);
} public static String valueOf(boolean b) {
return b ? "true" : "false";
}
public static String valueOf(char c) {
char data[] = { c };
return new String(data, true);
}
public static String valueOf(int i) {
return Integer.toString(i);
}
public static String valueOf(long l) {
return Long.toString(l);
}
public static String valueOf(float f) {
return Float.toString(f);
}
public static String valueOf(double d) {
return Double.toString(d);
}
java源码解析之String类(五)的更多相关文章
- java源码解析之String类(一)
String是我们接触最多的类,无论是学习中还是工作中,基本每天都会和字符串打交道,从字符串本身的各种拼接.切片.变形,再到和其他基本数据类型的转换,几乎无时无刻都在使用它,今天就让我们揭开Strin ...
- java源码解析之String类(三)
上一节我们主要讲了String类的一些不是很常用的方法,其中需要掌握的如下,我就不再赘述了 public int length() public boolean isEmpty() public by ...
- java源码解析之String类(二)
上一节主要介绍了String类的一些构造方法,主要分为四类 无参构造器:String(),创建一个空字符串"",区别于null字符串,""已经初始化,null并 ...
- java源码解析之String类(四)
/* * 返回指定字符第一次出现的字符串内的索引 */ public int indexOf(int ch) { return indexOf(ch, 0); } /* * 返回指定字符第一次出现的字 ...
- Java源码解析——集合框架(五)——HashMap源码分析
HashMap源码分析 HashMap的底层实现是面试中问到最多的,其原理也更加复杂,涉及的知识也越多,在项目中的使用也最多.因此清晰分析出其底层源码对于深刻理解其实现有重要的意义,jdk1.8之后其 ...
- java源码解析之Object类
一.Object类概述 Object类是java中类层次的根,是所有类的基类.在编译时会自动导入.Object中的方法如下: 二.方法详解 Object的方法可以分成两类,一类是被关键字fin ...
- [Java源码解析] -- String类的compareTo(String otherString)方法的源码解析
String类下的compareTo(String otherString)方法的源码解析 一. 前言 近日研究了一下String类的一些方法, 通过查看源码, 对一些常用的方法也有了更透彻的认识, ...
- 【Java源码解析】Thread
简介 线程本质上也是进程.线程机制提供了在同一程序内共享内存地址空间运行的一组线程.对于内核来讲,它就是进程,只是该进程和其他一下进程共享某些资源,比如地址空间.在Java语言里,Thread类封装了 ...
- AOP源码解析:AspectJAwareAdvisorAutoProxyCreator类的介绍
AspectJAwareAdvisorAutoProxyCreator 的类图 上图中一些 类/接口 的介绍: AspectJAwareAdvisorAutoProxyCreator : 公开了Asp ...
随机推荐
- 在Android手机上学习socket程序
我们都知道Android手机是基于Linux系统的,在没有Linux环境,但是想学习socket编程的同学可以在Android手机中试试,利用ndk编译可执行文件在Android手机中运行.不同于动态 ...
- HistCite 引文分析软件的利器
所需工具及网站清单, HISTCITE:DOWNLOAD YOUR FREE COPY. 提交自己的基本信息即可,十分简单: SCI数据库官网(web of science):http://apps. ...
- C#获取windows 10的下载文件夹路径
Windows没有为“下载”文件夹定义CSIDL,并且通过Environment.SpecialFolder枚举无法使用它. 但是,新的Vista 知名文件夹 API确实使用ID定义它FOLDERID ...
- EPPlus简单使用
在使用之前需要在项目中添加对EEPULS.dll的引用 1,创建excel 2,创建sheet 3,添加内容 4,修改 5,保存 FileInfo newFile = new FileInfo(fil ...
- XenServer重置存储管理SR至Ext3
Xenserver默认安装到本地磁盘,它是基于本地磁盘上Linux的LVM所管理,在xenserver创建为LVM Typer的本地SR,xenserver在LVM上不支持Thin Provision ...
- matlab 正态分布相关 API
randn:标准正太分布(μ=0,σ=1) normrnd:正态分布随机数,(需要手动指定 μ,σ,二者均是标量) mvnrnd:多变量正态分布随机数,(需要手动指定 μ,σ(二者为向量))
- 自定义 DependencyProperty 与 RoutedEvent
原文:自定义 DependencyProperty 与 RoutedEvent //自定义依赖属性 class MyBook : DependencyObject//依赖属性必须派生自Dependen ...
- Nginx 设置cors跨域
在我们的开发中,经常遇到跨域,这个时候,可以通过cors来解决. 解决的方法可以在服务端的代码层或者在web服务器进行设置 在web服务器上进行设置cors 跨域,这样就不必改动代码.以nginx为例 ...
- css3如何让div一直循环自转圈,附带:网络请求通知图片一直在转圈实例
css3如何让div一直循环自转圈 代码如下: div{ -webkit-transition-property: -webkit-transform; -webkit-transition-dura ...
- 原生Js监听普通dom尺寸变化
原生Js监听普通dom尺寸变化 具体做法有以下几种: 初始化项目后,轮询,反复查看 dom 尺寸是否变化,这种一听就感觉不好,开销太大. 监听元素的滚动事件,在 目标 dom 里面包裹一个同等大小的 ...