String-学习笔记(1)
String对象的不变性
对String对象的任何改变都不会影响到原对象,相关的任何change操作都会生成新的对象
例:
String str = "abc";
相当于
char data[] = {'a', 'b', 'c'};
String str = new String(data);
1、定义
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {}
-
final
表示此类无法被继承
-
java.io.Serializable
序列化的标记,该接口没有任何实现
-
CharSequence
字符序列,CharBuffer、String、StringBuffer、StringBuilder四个类都实现了这个接口
2、属性
/** The value is used for character storage. */
private final char value[];
String类用于存储数据的地方,可以看出String存储数据是基于char数组来实现的,由于声明为final,所以一旦初始化后就不能进行更改
/** Cache the hash code for the string */
private int hash; // Default to 0
字符串的hash值,默认为0
/** use serialVersionUID from JDK 1.0.2 for interoperability */
private static final long serialVersionUID = -6849794470754667710L;
由于实现了Serializable接口,所以可以为类添加serialVersionUID,添加后可以保证在进行序列化后进行反序列化时版本的一致性,如果不指定ID,如果修改类的状态JVM会根据类的状态为类生成一个新ID,这样反序列化后ID不一致而导致反序列化失败
/** Class String is special cased within the Serialization Stream Protocol.*/
private static final ObjectStreamField[] serialPersistentFields = new ObjectStreamField[0];
3、构造方法
String类中重载的构造方法比较多,这里列举几种常用的构造方法
-
基于字符串构造一个String
1、public String()
初始化一个新的字符串,value属性的值为""(空串)的字符数组
2、public String(String original)
基于传入的字符串构造一个String
-
基于字符数组构造一个String
1、public String(char value[])
方法调用链:Arrays.copyOf - > System.arraycopy
其中System.arraycopy是一个native方法,方法的作用是将传入的字符数组逐个的复制到String的value属性的字符数组中
2、public String(char value[], int offset, int count)
offset是起始位置,count,是复制的长度,调用链与1相同,但可以根据传入的字符数组指定复制的起始位置
-
基于整型数组构造一个String
1、public String(int[] codePoints, int offset, int count)
根据传入的整型数组构成String字符串
-
基于字节数组构造一个String(1-4的构造方法间接调用5、6的构造方法)
1、public String(byte bytes[])
2、public String(byte bytes[], int offset, int length)
3、public String(byte bytes[], Charset charset)
4、public String(byte bytes[], String charsetName)
5、public String(byte bytes[], int offset, int length, Charset charset)
6、public String(byte bytes[], int offset, int length, String charsetName)
将传入的byte[]数组转为String字符串的时候需要考虑编码与解码的问题,构造函数中的charsetName与charset可以指定将传进来的byte数组转为对应String的字符数组
在进行解码的的时候共有两种解码方法,分别是StringCoding类的两个重载方法:
1、static char[] decode(String charsetName, byte[] ba, int off, int len)
在调用如果没有指定字符编码,默认采用ISO-8859-1编码
String csn = (charsetName == null) ? "ISO-8859-1" : charsetName;
2、static char[] decode(Charset cs, byte[] ba, int off, int len)
在调用前必须指定相应解码器,否则抛出运行时异常
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);
}
-
基于StringBuffer和StringBuilder构造一个String
1、public String(StringBuilder builder)
2、public String(StringBuffer buffer)
对于StringBuilder和StringBuffer这两个类,可以直接使用重写的toString方法获取字符串,在效率上,StringBuilder比StringBuffer快一点,因为StringBuffer加了synchronized,使用了同步机制
StringBuffer:
@Override
public synchronized String toString() {
if (toStringCache == null) {
toStringCache = Arrays.copyOfRange(value, 0, count);
}
return new String(toStringCache, true);
}
StringBuilder:
@Override
public String toString() {
// Create a copy, don't share the array
return new String(value, 0, count);
}
-
一个非public的构造方法
1、String(char[] value, boolean share)
/*
* a separate constructor is needed because we already have a public
* String(char[]) constructor that makes a copy of the given char[].
*/
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
由注释可以看出,已经存在了public String(char[] value),加上boolean share只是为了进行重载之前存在的构造函数
这个构造方法的好处是无需像之前构造方法一样进行逐一复制,直接将属性value值指向新的引用数组。但这样就会破坏数组的不可变性,所以这个构造函数没有设置为Public
4、其他方法
-
public int length()
返回字符串长度
-
public boolean isEmpty()
判断字符串是否为空
-
public char charAt(int index)
返回字符串(index + 1)个字符
-
public int codePointAt(int index)
获取字符数组元素的代码点
-
public int codePointBefore(int index)
返回 char 数组的给定索引前面的代码点
-
public int codePointCount(int beginIndex, int endIndex)
返回的是代码点个数,是实际上的字符个数
-
public int offsetByCodePoints(int index, int codePointOffset)
返回指定索引处的字符
-
void getChars(char dst[], int dstBegin)
将字符从字符串复制到目标字符数组
-
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin)
将字符从字符串复制到目标字符数组
-
public int hashCode()
返回对应的hash值,如果两个字符串value值相同,那么它们的hash值一定相同,如果它们的hash值相同,它们的value值不一定相同
-
public int indexOf(int ch, int fromIndex)
在字符ch在字串fromindex位后出现的第一个位置
-
public int lastIndexOf(int ch, int fromIndex)
就是字符ch在字串fromindex位后出现的第一个位置
-
public int lastIndexOf(String str, int fromIndex)
返回指定字符串从fromIndex最后一次出现str的位置
-
public String substring(int beginIndex)
返回从beginIndex位置开始到最后的子字符串,对于substring方法,在java8中,将调用构造方法重写构建一个String,在Java7之前,substring方法返回的字符串中的value值指向被切割的字符数组,导致原来的字符串中的字符数组中只有一部分是有用的(substring方法返回的字符串),其余字符都是没用的,但是由于substring返回的字符串的引用,导致原来的字符串的整个字符数组都无法被释放
-
public String substring(int beginIndex, int endIndex)
返回从起始索引到结束索引的子符串,包含起始索引,但不包含结束索引
-
public CharSequence subSequence(int beginIndex, int endIndex)
返回相应字符串的子字符串,内部调用substring方法
-
public String concat(String str)
在指定字符串的末尾加上Str
-
public String replace(char oldChar, char newChar)
将字符串中指定的oldChar替换成newChar
-
public boolean matches(String regex)
判断字符串是否与给定的正则表达式匹配
-
contains(CharSequence s)
判断字符串是否包含对应的s子序列,内部使用indexOf
-
public String replaceAll(String regex, String replacement)
,用replacement替换所有的regex(正则表达式)匹配项
-
public String replaceFirst(String regex, String replacement)
和replaceAll相同,区别是只替换第一个匹配项
-
public String replace(CharSequence target, CharSequence replacement)
用replacement替换所有的target
-
public String[] split(String regex, int limit)
regex匹配的正则表达式
limit n 大于0,匹配n - 1 次
limit n 等于0,匹配无限次并且省略末尾的空字串
limit n 小于0,匹配无限次 -
public String[] split(String regex)
默认调用public String[] split(String regex, int limit),limit为0 -
public static String join(CharSequence delimiter, CharSequence... elements)
通过delimiter连接符,连接多个elements
-
public String toLowerCase()
将字符串转为小写
-
public String toUpperCase()
将字符串转为大写
-
public String trim()
去除字符串首尾空格
-
String toString()
返回当前字符串对象
-
public char[] toCharArray()
将字符串对象中的字符转换为字符数组
-
public static String format(String format, Object... args)
返回指定的格式化的字符串
-
public static String valueOf(Object obj)
将指定的obj对象转换为String,该方法也有基本类型作为参数的重载
-
public static String copyValueOf(char data[])
与valueOf方法类似,直接调用String构造方法创建新的String进行返回
-
public native String intern()
调用该方法后,如果字符串常量池中已经有一个相等的字符串常量则返回其引用,如果没有则将字符串常量添加到对象池中然后再返回该字符串常量的引用
-
public byte[] getBytes(String charsetName)
-
public byte[] getBytes(Charset charset)
可将一个字符串转为字节数组,String提供了很多getBytes重载方法。由于是字符串与字节数组的互相转换,所以涉及到编码问题,当使用不带参数的getBytes方法时,会使用系统默认编码,中文系统下会使用GBK或者GB2312进行编码,英文系统下会使用iso-8859-1进行编码。为了不依赖运行的机器环境,可以通过上面两个getBytes方法来指定编码方式。
-
boolean equals(Object anObject);
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;
}
比较两个字符串是否相同,相同返回true,不同返回false,equals方法在进行真正的字符数组比较前先做了一系列的判断,采用不符合条件就尽快return的方式,相比直接比较两个字符串的字符数组减少了很多开销
-
boolean contentEquals(StringBuffer sb);
比较两个字符串是否相同,相同返回true,不同返回false
-
boolean contentEquals(CharSequence cs);
public boolean contentEquals(CharSequence cs) {
// Argument is a StringBuffer, StringBuilder
if (cs instanceof AbstractStringBuilder) {
if (cs instanceof StringBuffer) {
synchronized(cs) {
return nonSyncContentEquals((AbstractStringBuilder)cs);
}
} else {
return nonSyncContentEquals((AbstractStringBuilder)cs);
}
}
比较两个字符串是否相同,相同返回true,不同返回false,与上一个区别只是传入参数不同,在调用比较方法之前先判断是否属于AbstractStringBuilder,再判断是否是线程安全的类,最后再调用各自的方法,也就是先比较大的范围,再范围减小进行比较
-
boolean equalsIgnoreCase(String anotherString);
比较两个字符串是否相同,与前面几个方法的区别在于比较前先全部转为大写
-
int compareTo(String anotherString);
int compareToIgnoreCase(String str);
boolean regionMatches(int toffset, String other, int ooffset,int len) //局部匹配
boolean regionMatches(boolean ignoreCase, int toffset,String other, int ooffset, int len) //局部匹配
5、对"+"字符的重载
"+"是java中唯一的重载运算符,底层使用的是StringBuilder类的append方法和toString方法
public static void main(String[] args) {
String string1="Hard";
String string2 = string1 + "wjj";
}
反编译后:
public static void main(String[] args) {
String string1 = "Hard";
String string2 = new
StringBuilder().append(string1).append("wjj").toString();
}
6、将int转为字符串
1.int i = 5;
2.String i1 = "" + i;
3.String i2 = String.valueOf(i);
4.String i3 = Integer.toString(i);
第2个式子涉及到"+"的重载,调用过程和标题5一样,3和4的调用方式是一样的
public static String valueOf(int i) {
return Integer.toString(i);
}