文章目录
- 从哪几个方面了解String
- 一、 String的定义
- 二、 字段属性
- 三、构造函数
- 10、String() 构造方法的作用
- 11、String(byte[] bytes) 的作用
- 12、用String(byte[] bytes)构造方法举个例子
- 13、String(byte[] bytes, Charset charset) 的作用
- 14、Charset 类型的作用
- 15、String(byte[] bytes, int offset, int length) 的作用
- 16、用String(byte[] bytes, int offset, int length)构造方法举例
- 17、String(byte[] bytes, int offset, int length, Charset charset)的作用
- 18、Charset类型所在包
- 19、String(byte[] bytes, int offset, int length, String charsetName)的作用
- 20、String(byte[] bytes, String charsetName) 的作用
- 21、String(char[] value) 的作用
- 四、API
从哪几个方面了解String
String的定义、字段属性、构造函数、API
一、 String的定义
1、 String的表面定义
public final class String implements java.io.Serializable, Comparable<String>, CharSequence
2、 String是一个可继承的类吗?为什么?
String是一个final类,既不能被继承的类
3、 String类实现了java.io.Serializable接口的作用–>1
实现序列化
4、String类实现了Comparable接口的作用
可以用于比较大小(按顺序比较单个字符的ASCII码)
5、String类实现了 CharSequence 接口的作用
表示是一个有序字符的序列,因为String的本质是一个char类型数组
二、 字段属性
6、private final char value[]; 的作用
/** The value is used for character storage. */
private final char value[];
用来存字节的。这是String字符串的本质,是一个字符集合,而且是final的,是不可变的。
7、该成员变量被final修饰之后产生的效果
表示该字符串是不可变的。
8、private int hash;的作
/** Cache the hash code for the string */
private int hash; // Default to 0
缓存字符串的哈希值,默认是0
9、private static final long serialVersionUID = -6849794470754667710L;的作用
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
三、构造函数
10、String() 构造方法的作用
是空参构造方法
11、String(byte[] bytes) 的作用
通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String
。
12、用String(byte[] bytes)构造方法举个例子
byte[] bytes = {97,98,99,100};
String str = new String(bytes);
System.out.println(str);
the output:abcd
13、String(byte[] bytes, Charset charset) 的作用
通过使用指定的 charset 解码指定的 byte 数组,构造一个新的
String
。
14、Charset 类型的作用
指定解码类型,比如GBK,UTF-8等
15、String(byte[] bytes, int offset, int length) 的作用
通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String
。新 String
的长度是字符集的函数,因此可能不等于该子数组的长度。
参数:
bytes - 要解码为字符的 byte
offset - 要解码的第一个 byte 的索引
length - 要解码的 byte 数
抛出:
IndexOutOfBoundsException - 如果 offset
和 length
参数索引字符超出 bytes
数组的范围
16、用String(byte[] bytes, int offset, int length)构造方法举例
byte[] bytes = {97,98,99,100};
String str = new String(bytes,2,2);
System.out.println(str);
the output:cd
17、String(byte[] bytes, int offset, int length, Charset charset)的作用
参数:
bytes
- 要解码为字符的 byte
offset
- 要解码的第一个 byte 的索引
length
- 要解码的 byte 数
charset-用来解码 bytes的 charset
18、Charset类型所在包
java.nio.charset
类 Charset
java.lang.Object
java.nio.charset.Charset
所有已实现的接口:
Comparable<Charset>
19、String(byte[] bytes, int offset, int length, String charsetName)的作用
String
public String(byte[] bytes,
int offset,
int length,
String charsetName)
throws UnsupportedEncodingException
通过使用指定的字符集解码指定的 byte 子数组,构造一个新的 String
。新 String
的长度是一个字符集函数,因此可能不等于子数组的长度。
当给定 byte 在给定字符集中无效的情况下,此构造方法的行为没有指定。如果需要对解码过程进行更多控制,则应该使用 CharsetDecoder
类。
参数:
bytes
- 要解码为字符的 byte
offset
- 要解码的第一个 byte 的索引
length
- 要解码的 byte 数
charsetName
- 受支持 charset 的名称
抛出:
UnsupportedEncodingException - 如果指定的字符集不受支持
IndexOutOfBoundsException - 如果 offset
和 length
参数索引字符超出 bytes
数组的范围
从以下版本开始:
JDK1.1
20、String(byte[] bytes, String charsetName) 的作用
通过使用指定的 charset 解码指定的 byte 数组,构造一个新的
String
。
21、String(char[] value) 的作用
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
四、API
22、长度
public int length() {
//所以String的长度就是一个value的长度
return value.length;
}
23、是否为空函数
public boolean isEmpty() {
//当char数组的长度为0,则代表String为"",空字符串
return value.length == 0;
}
24、charAt函数
/**
* 返回String对象的char数组index位置的元素
*/
public char charAt(int index) {
if ((index < 0) || (index >= value.length)) {
//index不允许小于0,不允许大于等于String的长度
throw new StringIndexOutOfBoundsException(index);
}
return value[index]; //返回
}
- 只有一个charAt()是针对字符而言的,就是寻找第index位置的字符是什么,在面试的算法中也很常会用到
25、codePointAt函数
/**
* 返回String对象的char数组index位置的元素的ASSIC码(int类型)
*/
public int codePointAt(int index) {
if ((index < 0) || (index >= value.length)) {
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointAtImpl(value, index, value.length);
}
26、codePointBefore函数
/**
* 返回index位置元素的前一个元素的ASSIC码(int型)
*/
public int codePointBefore(int index) {
int i = index - 1;//获得index前一个元素的索引位置
if ((i < 0) || (i >= value.length)) {//所以,index不能等于0,因为i = 0 - 1 = -1
throw new StringIndexOutOfBoundsException(index);
}
return Character.codePointBeforeImpl(value, index, 0);
}
27、codePointCount函数
/**
* 方法返回的是代码点个数,是实际上的字符个数,功能类似于length()
* 对于正常的String来说,length方法和codePointCount没有区别,都是返回字符个数。
* 但当String是Unicode类型时则有区别了。
* 例如:String str = “/uD835/uDD6B” (即使 'Z' ), length() = 2 ,codePointCount() = 1
*/
public int codePointCount(int beginIndex, int endIndex) {
if (beginIndex < 0 || endIndex > value.length || beginIndex > endIndex) {
throw new IndexOutOfBoundsException();
}
return Character.codePointCountImpl(value, beginIndex, endIndex - beginIndex);
}
28、offsetByCodePoints
/**
* 也是相对Unicode字符集而言的,从index索引位置算起,偏移codePointOffset个位置,返回偏移后的位置是多少
* 例如,index = 2 ,codePointOffset = 3 ,maybe返回 5
*/
public int offsetByCodePoints(int index, int codePointOffset) {
if (index < 0 || index > value.length) {
throw new IndexOutOfBoundsException();
}
return Character.offsetByCodePointsImpl(value, 0, value.length,
index, codePointOffset);
}
29、getChar函数
/**
* 这是一个不对外的方法,是给String内部调用的,因为它是没有访问修饰符的,只允许同一包下的类访问
* 参数:dst[]是目标数组,dstBegin是目标数组的偏移量,既要复制过去的起始位置(从目标数组的什么位置覆盖)
* 作用就是将String的字符数组value整个复制到dst字符数组中,在dst数组的dstBegin位置开始拷贝
*
*/
void getChars(char dst[], int dstBegin) {
System.arraycopy(value, 0, dst, dstBegin, value.length);
}
30、equals方法的实现
/**
- String的equals方法,重写了Object的equals方法(区分大小写)
- 比较的是两个字符串的值是否相等
- 参数是一个Object对象,而不是一个String对象。这是因为重写的是Object的equals方法,所以是Object
- 如果是String自己独有的方法,则可以传入String对象,不用多此一举
-
- 实例:str1.equals(str2)
*/
public boolean equals(Object anObject) {
if (this == anObject) { //首先判断形参str2是否跟当前对象str1是同一个对象,既比较地址是否相等
return true; //如果地址相等,那么自然值也相等,毕竟是同一个字符串对象
}
if (anObject instanceof String) { //判断str2对象是否是一个String类型,过滤掉非String类型的比较
String anotherString = (String)anObject; //如果是String类型,转换为String类型
int n = value.length; //获得当前对象str1的长度
if (n == anotherString.value.length) { //比较str1的长度和str2的长度是否相等
//如是进入核心算法
char v1[] = value; //v1为当前对象str1的值,v2为参数对象str2的值
char v2[] = anotherString.value;
int i = 0; //就类似于for的int i =0的作用,因为这里使用while
while (n-- != 0) { //每次循环长度-1,直到长度消耗完,循环结束
if (v1[i] != v2[i]) //同索引位置的字符元素逐一比较
return false; //只要有一个不相等,则返回false
i++;
}
return true; //如比较期间没有问题,则说明相等,返回true
}
}
return false;
}
31、equalsIgnoreCase
/**
* 这也是一个String的equals方法,与上一个方法不用,该方法(不区分大小写),从名字也能看出来
* 是对String的equals方法的补充。
* 这里参数这是一个String对象,而不是Object了,因为这是String本身的方法,不是重写谁的方法
*/
public boolean equalsIgnoreCase(String anotherString) {
return (this == anotherString) ? true //一样,先判断是否为同一个对象
: (anotherString != null)
&& (anotherString.value.length == value.length) //再判断长度是否相等
&& regionMatches(true, 0, anotherString, 0, value.length); //再执行regionMatchs方法
}
equalsIgnoreCase()
方法是对equals()方法补充,不区分大小写的判断
32、contentEquals方法
/**
* 这是一个公有的比较方法,参数是StringBuffer类型
* 实际调用的是contentEquals(CharSequence cs)方法,可以说是StringBuffer的特供版
*/
public boolean contentEquals(StringBuffer sb) {
return contentEquals((CharSequence)sb);
}
/**
* 这是一个私有方法,特供给比较StringBuffer和StringBuilder使用的。
* 比如在contentEquals方法中使用,参数是AbstractStringBuilder抽象类的子类
*
*/
private boolean nonSyncContentEquals(AbstractStringBuilder sb) {
char v1[] = value; //当前String对象的值
char v2[] = sb.getValue(); //AbstractStringBuilder子类对象的值
int n = v1.length; //后面就不说了,其实跟equals方法是一样的,只是少了一些判断
if (n != sb.length()) {
return false;
}
for (int i = 0; i < n; i++) {
if (v1[i] != v2[i]) {
return false;
}
}
return true;
}
/**
* 这是一个常用于String对象跟StringBuffer和StringBuilder比较的方法
* 参数是StringBuffer或StringBuilder或String或CharSequence
* StringBuffer和StringBuilder和String都实现了CharSequence接口
*/
public boolean contentEquals(CharSequence cs) {
// Argument is a StringBuffer, StringBuilder
if (cs instanceof AbstractStringBuilder) { //如果是AbstractStringBuilder抽象类或其子类
if (cs instanceof StringBuffer) { //如果是StringBuffer类型,进入同步块
synchronized(cs) {
return nonSyncContentEquals((AbstractStringBuilder)cs);
}
} else { //如果是StringBuilder类型,则进入非同步块
return nonSyncContentEquals((AbstractStringBuilder)cs);
}
}
/***下面就是String和CharSequence类型的比较算法*****/
// Argument is a String
if (cs instanceof String) {
return equals(cs);
}
// Argument is a generic CharSequence
char v1[] = value;
int n = v1.length;
if (n != cs.length()) {
return false;
}
for (int i = 0; i < n; i++) {
if (v1[i] != cs.charAt(i)) {
return false;
}
}
return true;
}
contentEquals()
则是用于String对象与4种类型的判断,通常用于跟StringBuilder和StringBuffer的判断,也是对equals方法的一个补充
33、regionMatchs()方法
/**
* 这是一个类似于equals的方法,比较的是字符串的片段,也即是部分区域的比较
* toffset是当前字符串的比较起始位置(偏移量),other是要比较的String对象参数,ooffset是要参数String的比较片段起始位置,len是两个字符串要比较的片段的长度大小
*
* 例子:String str1 = "0123456",Str2 = "0123456789";
* str1.regionMatchs(0,str2,0,6);意思是str1从0位置开始于str2的0位置开始比较6个长度的字符串片段
* 相等则返回 true,不等返回false
*/
public boolean regionMatches(int toffset, String other, int ooffset,
int len) {
char ta[] = value; //当前对象的值
int to = toffset; //当前对象的比较片段的起始位置,既偏移量
char pa[] = other.value; //参数,既比较字符串的值
int po = ooffset; //比较字符串的起始位置
// Note: toffset, ooffset, or len might be near -1>>>1.
if ((ooffset < 0) || (toffset < 0)//起始位置不小于0或起始位置不大于字符串长度 - 片段长度,大于就截取不到这么长的片段了
|| (toffset > (long)value.length - len)
|| (ooffset > (long)other.value.length - len)) {
return false; //惊讶脸,居然不是抛异常,而是返回false
}
while (len-- > 0) { //使用while循环,当然也可以使for循环
if (ta[to++] != pa[po++]) { //片段区域的字符元素逐个比较
return false;
}
}
return true;
}
/**
* 这个跟上面的方法一样,只不过多了一个参数,既ignoreCase,既是否为区分大小写。
* 是equalsIgnoreCase()方法的片段比较版本,实际上equalsIgnoreCase()也是调用regionMatches函数
*/
public boolean regionMatches(boolean ignoreCase, int toffset,
String other, int ooffset, int len) {
char ta[] = value;
int to = toffset;
char pa[] = other.value;
int po = ooffset;
// Note: toffset, ooffset, or len might be near -1>>>1.
if ((ooffset < 0) || (toffset < 0)
|| (toffset > (long)value.length - len)
|| (ooffset > (long)other.value.length - len)) {
return false;
}
while (len-- > 0) {
char c1 = ta[to++];
char c2 = pa[po++];
if (c1 == c2) {
continue;
}
if (ignoreCase) {
// If characters don't match but case may be ignored,
// try converting both characters to uppercase.
// If the results match, then the comparison scan should
// continue.
char u1 = Character.toUpperCase(c1);
char u2 = Character.toUpperCase(c2);
if (u1 == u2) {
continue;
}
// Unfortunately, conversion to uppercase does not work properly
// for the Georgian alphabet, which has strange rules about case
// conversion. So we need to make one last check before
// exiting.
if (Character.toLowerCase(u1) == Character.toLowerCase(u2)) {
continue;
}
}
return false;
}
return true;
}
34、compareTo类函数和CaseInsensitiveComparator静态内部类
/**
* 这是一个比较字符串中字符大小的函数,因为String实现了Comparable<String>接口,所以重写了compareTo方法
* Comparable是排序接口。若一个类实现了Comparable接口,就意味着该类支持排序。
* 实现了Comparable接口的类的对象的列表或数组可以通过Collections.sort或Arrays.sort进行自动排序。
*
* 参数是需要比较的另一个String对象
* 返回的int类型,正数为大,负数为小,是基于字符的ASSIC码比较的
*
*/
public int compareTo(String anotherString) {
int len1 = value.length; //当前对象的长度
int len2 = anotherString.value.length; //比较对象的长度
int lim = Math.min(len1, len2); //获得最小长度
char v1[] = value; //获得当前对象的值
char v2[] = anotherString.value; //获得比较对象的值
int k = 0; //相当于for的int k = 0,就是为while循环的数组服务的
while (k < lim) { //当当前索引小于两个字符串中较短字符串的长度时,循环继续
char c1 = v1[k]; //获得当前对象的字符
char c2 = v2[k]; //获得比较对象的字符
if (c1 != c2) { //从前向后遍历,只要其实一个不相等,返回字符ASSIC的差值,int类型
return c1 - c2;
}
k++;
}
return len1 - len2; //如果两个字符串同样位置的索引都相等,返回长度差值,完全相等则为0
}
/**
* 这时一个类似compareTo功能的方法,但是不是comparable接口的方法,是String本身的方法
* 使用途径,我目前只知道可以用来不区分大小写的比较大小,但是不知道如何让它被工具类Collections和Arrays运用
*
*/
public int compareToIgnoreCase(String str) {
return CASE_INSENSITIVE_ORDER.compare(this, str);
}
/**
* 这是一个饿汉单例模式,是String类型的一个不区分大小写的比较器
* 提供给Collections和Arrays的sort方法使用
* 例如:Arrays.sort(strs,String.CASE_INSENSITIVE_ORDER);
* 效果就是会将strs字符串数组中的字符串对象进行忽视大小写的排序
*
*/
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
/**
* 这一个私有的静态内部类,只允许String类本身调用
* 实现了序列化接口和比较器接口,comparable接口和comparator是有区别的
* 重写了compare方法,该静态内部类实际就是一个String类的比较器
*
*/
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 8575799808933029326L;
public int compare(String s1, String s2) {
int n1 = s1.length(); //s1字符串的长度
int n2 = s2.length(); //s2字符串的长度
int min = Math.min(n1, n2); //获得最小长度
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i); //逐一获得字符串i位置的字符
char c2 = s2.charAt(i);
if (c1 != c2) { //部分大小写比较一次
c1 = Character.toUpperCase(c1); //转换大写比较一次
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
c1 = Character.toLowerCase(c1); //转换小写比较一次
c2 = Character.toLowerCase(c2);
if (c1 != c2) { //返回字符差值
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2; //如果字符相等,但是长度不等,则返回长度差值,短的教小,所以小-大为负数
}
/** Replaces the de-serialized object. */
private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
}
以上的代码可以看出:
以上的最大问题可以能就是为什么要有个静态内部类,为什么实现了compareTo又有compare,移步到下面,有解答
String实现了comparable接口,重写了compareTo方法,可以用于自己写类进行判断排序,也可以使用collections,Arrays工具类的sort进行排序。只有集合或数组中的元素实现了comparable接口,并重写了compareTo才能使用工具类排序。
//返回字符差值
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2; //如果字符相等,但是长度不等,则返回长度差值,短的教小,所以小-大为负数
}
/** Replaces the de-serialized object. */
private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
}
以上的代码可以看出:
以上的最大问题可以能就是为什么要有个静态内部类,为什么实现了compareTo又有compare,移步到下面,有解答
String实现了comparable接口,重写了compareTo方法,可以用于自己写类进行判断排序,也可以使用collections,Arrays工具类的sort进行排序。只有集合或数组中的元素实现了comparable接口,并重写了compareTo才能使用工具类排序。
- `CASE_INSENSITIVE_ORDER`是一个单例,是String提供为外部的比较器,该比较器的作用是忽视大小写进行比较,我们可以通过Collections或Arrays的sort方法将CASE_INSENSITIVE_ORDER比较器作为参数传入,进行排序。