String常用的api
- int length
- int indexOf(int ch) 查找ch字符在该字符中第一次出现的位置
- int indexOf(String str) 查找str字符串第一次出现的位置
- int lastIndexOf(int ch) 查找ch字符串最后一次出现的位置
- String substring(int beginIndex) 获取从beginIndex位置开始到结束的子字符串
- string substring(int beginIndex,int endIndex)
- String trim() 去除了前后空格的字符串
- boolean equals()
- String toLowerCase()
- char charAt()
- String[] split(String regex)
- byte getBytes()
String特性
String类是不可变对象:
- 类内部所有的字段都是final修饰的
- 类内部所有字段都是私有的,private
- 类不能继承和拓展
- 没有对外提供修改内部状态的方法,比如sette方法
- 类内部的字段如果是引用,不能获取这个引用
String原理
String str="张三";
str="李四";
上面代码并没有改变str,是重新创建了一个String对象李四,把str的引用指向地址改变而已
源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
...
String其实就是一个字符数组,一个个字符存储在数组中,但是value没有setter方法,所以不能在外部改变,真正改变的是value的地址
疑惑
内部的方法substring,replace等方法是怎么操作的?
每次使用这些操作,其实是在堆内存中创建了一个新的对象,然后value指向不同的对象
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);
}
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);
}
在判断没有outofbound后,用构造方法new一个新的String对象
怎么改变string
反射机制,违反语言设计原则
public class TestString {
@Test
public void testString() {
String str = "张三";
System.out.println(str);
try {
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);//私有属性必须写这句
char[] value;
value=(char[]) field.get(str);//获取对象的值
//更改字符
value[0]='老';
System.out.println(str);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
这样就把这个字符串给修改了
为什么把String设置为不可变
- String的类型使用是最多的,在进行增删改查时,jvm需要检查这个String对象的安全性,通过hashcode确定String的唯一性,提高效率
- 字符串保留在常量池中,如果允许改变将产生各种错误