目录
String是一个final类,代表不可变的字符序列,不能被继承。字符串是常量,它的值在创建之后不能更改。
String实现了Serializeble接口:表示字符串是支持可序列化的。
String实现了Comparable接口:表示字符串可以比较大小(字典序)。
String的不可变性
1. 当对字符串重新赋值时,需要重新指定内存区域赋值,不能使用原来的字符串进行赋值。
String s1 = "abc"; //字面量
String s2 = "abc";
System.out.println(s1 == s2); //true
s1 = "hello";
System.out.println(s1 == s2); //false
System.out.println(s1); //hello
System.out.println(s2); //abc
字符串常量池中是不会存储相同内容的字符串。所以重新赋值前 s1 == s2,指向同一个字符串。由于String是不可变的,所以不能在原来的字符串重新赋值,只能在新的地方重新定义一个字符串。修改后,s2指向的字符串“abc”没修改,s1指向新的字符串“hello”。
2. 当对现有的字符串进行连接操作时,需要重新指定内存区域赋值,不能修改原来的字符串。
String s1 = "abc";
String s2 = "abc";
s1 += "def";
System.out.println(s1); //abcdef
System.out.println(s2); //abc
3. 当调用使用String的replace()方法修改字符或字符串时,需要重新指定内存区域赋值,不能修改原来的字符串。
String s1 = "abc";
String s2 = s1.replace('a', 'b');
System.out.println(s1); //abc
System.out.println(s2); //bbc
String不同实例化的对比
String s1 = "abc";
//this.value = "".value;
String s2 = new String();
//this.value = original.value;
String s3 = new String(String original);
String s4 = new String(char value[]);
String s5 = new String(char value[],int stratIndex,int count);
Q:String s1 = “abc”; 和 String s2 = new String(“abc”); 的区别?
A:通过字面量的方式给一个字符串赋值,此时的字符串声明在字符串常量池,可以共享。通过new的方式给一个字符串赋值,此时对象声明在堆中,对象中存了一个指向字符串常量池的地址。
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1 == s2); //true
System.out.println(s1 == s3); //false
System.out.println(s2 == s4); //false
System.out.println(s3 == s4); //false(两个不同的对象)
Person p1 = new Person("abc",10);
Person p2 = new Person("abc",10);
Person p3 = new Person(new String("abc"),10);
System.out.println(p1 == p2); //false
System.out.println(p1 == p3); //false
System.out.println(p1.getName() == p2.getName()); //true
System.out.println(p1.getName() == p3.getName()); //false
Q:String s = new String(“abc”); 在内存创建了几个对象?
A:两个。一个在堆,一个在字符串常量池。
String不同拼接方式的对比
String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";
String s4 = "hello" + "world";
String s5 = s1 + "world";
String s6 = "hello" + s2;
String s7 = s1 + s2;
String s8 = s5.intern();
System.out.println(s3 == s4); //ture
System.out.println(s3 == s5); //false
System.out.println(s3 == s6); //false
System.out.println(s3 == s7); //false
System.out.println(s5 == s6); //false
System.out.println(s5 == s7); //false
System.out.println(s6 == s7); //false
System.out.println(s3 == s8); //true
常量与常量的拼接结果在字符串常量池,且常量池不会存在相同内容的常量。
只要其中有一个是变量,结果就是一个在堆中的对象。
如果拼接结果调用intern()方法,返回值就在常量池中。
String的常用方法
|——int length()
|——boolean isEmpty()
|——char charAt(int index):返回指定索引的字符
|——byte[] getBytes()
|——boolean equals(Object anObject)
|——boolean equalsIgnoreCase(String anotherString):判断内容是否相等,忽略大小写
|——int compareTo(String anotherString)
|——boolean startsWith(String prefix)
|——boolean startsWith(String prefix, int toffset)
|——boolean endsWith(String suffix)
|——int hashCode()
|——int indexOf(String str):返回指定子串在此字符串第一次出现的索引
String——|——int indexOf(String str, int fromIndex)
|——int lastIndexOf(int ch)
|——int lastIndexOf(int ch, int fromIndex):返回指定子串在此字符串最后一次出现的索引,从指定的索引开始反向搜索
|——String substring(int beginIndex)
|——String substring(int beginIndex, int endIndex):获取子串(左闭右开)
|——String replace(char oldChar, char newChar)
|——String replace(CharSequence target, CharSequence replacement)
|——boolean matches(String regex)
|——boolean contains(CharSequence s)
|——String[] split(String regex):根据正则表达式分割字符串
|——String toLowerCase():所有字符转换为小写
|——String toUpperCase():所有字符转换为大写
|——String trim():去除字符串前后空格
|——char[] toCharArray()
|——String valueOf(int i)
String与基本数据类型之间的转换
字符串——▷基本数据类型、包装类
String——byte:Byte.parseByte(String s);
String——short:Short.parseShort(String s);
String——int:Integer.parseInt(String s);
String——long:Long.parseLong(String s);
String——float:Float.parseFloat(String s);
String——double:Double.parseDouble(String s);
String——boolean:Boolean.parseBoolean(String s);
基本数据类型、包装类——▷字符串
String.valueOf(char c);
String.valueOf(int i);
String.valueOf(long l);
String.valueOf(float f);
String.valueOf(double d);
String.valueOf(boolean b);
String与char[]之间的转换
字符串——▷char[]
public char[] toCharArray();
char[]——▷字符串
new String(char[] c);
new String(char[] c, int offset, int length);
String与byte[]之间的转换
字符串——▷byte[]
public byte[] getBytes();
public byte[] getBytes(String charsetName);
byte[]——▷字符串
new String(byte[] b);
new String(byte[] c, int offset, int length);
StringBuffer | StringBuilder
Q:String、StringBuffer、StringBuilder三者的效率?
A:StringBuilder > StringBuffer > String
Q:String、StringBuffer、StringBuilder三者的异同?
A:String:不可变字符序列。底层使用byte[] value存储。
StringBuffer:可变字符序列。线程安全,效率低。底层使用byte[] value存储。
StringBuilder:可变字符序列。线程不安全,效率高。底层使用byte[] value存储。
我们以StringBuilder为例,分析一下源码,StringBuffer和StringBuilder区别不大,StringBuffer多了一个synchronized关键字。
默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新数组。
public final class StringBuilder extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
...
public StringBuilder() {
super(16); //创建长度为16的数组
}
public StringBuilder(int capacity) {
super(capacity);
}
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
...
AbstractStringBuilder(int capacity) {
if (COMPACT_STRINGS) {
value = new byte[capacity];
coder = LATIN1;
} else {
value = StringUTF16.newBytesFor(capacity);
coder = UTF16;
}
}
...
public StringBuilder append(String str) {
super.append(str);
return this;
}
...
public AbstractStringBuilder append(String str) {
if (str == null) {
return appendNull();
}
int len = str.length();
ensureCapacityInternal(count + len);
putStringAt(count, str); //添加成功
count += len; //字符数增加
return this;
}
...
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
if (minimumCapacity - oldCapacity > 0) { //是否需要扩容
value = Arrays.copyOf(value,newCapacity(minimumCapacity) << coder);
}
}
...
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
int newCapacity = (oldCapacity << 1) + 2; //长度变为原来的2倍+2
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0) ? hugeCapacity(minCapacity) : newCapacity;
}
注意里面有一个方法length(),它返回的是当前字符的总数。而不是底层数组的长度。
StringBuilder builder = new StringBuilder();
builder.append("abc");
System.out.println(builder.length());
运行结果:3
int count; //The count is the number of characters used.
public int length() {
return count;
}
StringBuilder的常用方法
|——StringBuilder append(xxx):用于字符串拼接,其中提供了很多的append()方法。
|——StringBuilder delete(int start, int end):删除指定位置的内容,左闭右开
|——StringBuilder replace(int start, int end, String str):把[start,end)的内容替换为str,左闭右开
|——StringBuilder insert(int offset, xxx):指定位置插入xxx
|——StringBuilder reverse():把当前字符序列倒序
StringBuilder——|——int indexOf(String str)
|——String substring(int start, int end)
|——int length()
|——char charAt(int n)
|——void setCharAt(int n, char ch)
如有错误请大家指出了(ง •̀_•́)ง (*•̀ㅂ•́)و