String 类对象代表不可变的Unicode字符序列,因此我们可以将String对象称为“不可变对象”。
String类的substring方法
public String substring(int beginIndex)
返回一个字符串,该字符串是此字符串的子字符串。 子字符串以指定索引处的字符开头,并扩展到该字符串的末尾。
public String substring(int beginIndex, int endIndex)
返回一个字符串,该字符串是此字符串的子字符串。 子串开始于指定
beginIndex
并延伸到字符索引endIndex - 1
。 因此,子串的长度为endIndex-beginIndex
。
public class Test{
public static void main(String[] args) {
String str = "abcdefg";
String b1 = str.substring(2, 5);
System.out.println(b1);
String b2 = str.substring(3);
System.out.println(b2);
}
}
输出结果:
cde
defg
substring()是对字符串的截取操作,但本质是读取原字符串内容生成了新的字符串。
substring方法源码:
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);
}
其中,String构造方法源码:
public String(char value[], int offset, int count) {
if (offset < 0) {
throw new StringIndexOutOfBoundsException(offset);
}
if (count <= 0) {
if (count < 0) {
throw new StringIndexOutOfBoundsException(count);
}
if (offset <= value.length) {
this.value = "".value;
return;
}
}
// Note: offset or count might be near -1>>>1.
if (offset > value.length - count) {
throw new StringIndexOutOfBoundsException(offset + count);
}
this.value = Arrays.copyOfRange(value, offset, offset+count);
}
其中,copyOfRange方法源码:
public static char[] copyOfRange(char[] original, int from, int to) {
int newLength = to - from;
if (newLength < 0)
throw new IllegalArgumentException(from + " > " + to);
char[] copy = new char[newLength];
System.arraycopy(original, from, copy, 0,
Math.min(original.length - from, newLength));
return copy;
}
其中,arraycopy是一个本地方法(native)。
API说明:
String
public String(byte[] bytes, int offset, int length)通过使用平台的默认字符集解码指定的字节子阵列来构造新的
String
。 新的String
的长度是字符集的函数,因此可能不等于子数组的长度。指定字节在默认字符集中无效时,此构造函数的行为是未指定的。 当需要更多的解码过程控制时,应使用
CharsetDecoder
类。参数
bytes
- 要解码为字符的字节
offset
- 要解码的第一个字节的索引
length
- 要解码的字节数异常
IndexOutOfBoundsException
- 如果offset
和length
参数的索引字符在bytes
数组的边界之外从以下版本开始:
JDK1.1
public class Test{
public static void main(String[] args) {
char value[] = {'s', 't', 'u', 'd', 'y', ' ', 'j', 'a', 'v', 'a'};
String s = new String(value, 3, 5);
System.out.println(s);
}
}
输出结果:
dy ja
字符串比较
public static void main(String[] args) {
//编译器做了优化,直接在编译的时候将字符串进行拼接
String str1 = "hello" + " java";//相当于str1 = "hello java";
String str2 = "hello java";
System.out.println(str1 == str2);//true
String str3 = "hello";
String str4 = " java";
//编译的时候不知道变量中存储的是什么,所以没办法在编译的时候优化
String str5 = str3 + str4;
System.out.println(str2 == str5);//false
}
输出结果:
true
false
StringBuffer和StringBuilder
StringBuffer和StringBuilder非常类似,均代表可变的字符序列。 这两个类都是抽象类AbstractStringBuilder的子类,方法几乎一模一样。
public class Test {
public static void main(String[] args) {
StringBuilder str = new StringBuilder("abcdefg");
System.out.println(Integer.toHexString(str.hashCode()));
System.out.println(str);
str.setCharAt(2, 'M');
System.out.println(Integer.toHexString(str.hashCode()));
System.out.println(str);
}
}
输出结果:
2f7a2457
abcdefg
2f7a2457
abMdefg
地址一样,说明是同一个对象,是可变的字符必须列。