主要记录java中的String赋值及比较的问题以及StringBuffer和StringBuilder
- 比较:==和.equals
- 赋值:= 和 new String(“”)
比较:==和.equals
java中,除了基本数据类型(int, short, long, byte, char, boolean, float, double)存储的是值本身外,其他的数据类型存储的都是对象的引用(或者称为对象的地址)。
int a = 1, b = 1;
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(a == b); //true
System.out.println(str1 == str2); //false
a,b存储的都是1这个值。
而str1,str2存储的是新建的String对象的地址,两个地址不同。
//接上
System.out.println(str1.equals(str2)); //true
查看java源码中对于String的equals方法的实现:
/**
该方法覆盖了Object中的equals方法,其实不仅是String,Integer、Double等都对Object的equals方法实现了重写
*/
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;
}
赋值:= 和 new String(“”)
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2); //true
何故?
查阅资料,解释如下:
使用”=”为String变量赋值时,会先在字符串缓冲区查找有没有该字符串,若没有,则在字符串缓冲区新建该字符串,并将地址返回;若有,则直接将该字符串在缓冲区的地址付给变量。
使用”new String()”时,首先也会去缓冲区里边查找,不管有没有,它都会在堆里新建一个该字符串对象并返回该对象的地址,如果缓冲区里面没有,则在缓冲区里面也新建一个。
String str1 = "hello world";
String str2 = "hello";
/**
"hello"+" world"在编译的过程中间就将加直接处理成了"hello world";
而str2+" world"则被处理为new StringBuffer("hello").append(" world").toString();
*/
System.out.println(str1 == "hello"+" world"); //true
System.out.println(str1 == str2+" world"); //false
StringBuffer
StringBuffer和String都用来表示字符串,但两者是不同的类。
StringBuffer在进行字符串处理时,不生成新的对象,在内存使用上要优于String类。
StringBuffer在实现上和String一样同样适用char[]。但在append操作时,使用System.copyarray()方法(该方法会经常出现),提高了效率。
StringBuffer是线程安全的
StringBuffer在拼接字符串时的方法:
public StringBuffer append(String s)
StringBuilder
StringBuilder和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的,但速度比StringBuffer快(不能同步访问)。
String, StringBuffer, StringBuilder都不是java基本类型,而是类。
三者在存储数据事都是用char[] value.
不同之处在于String的value被final修饰过,其他两者没有。
String的内部实现
public final class String implements ... {
/** The value is used for character storage. */
private final char value[];
可以看出,String内部是使用char数组来保存数据的。value值被final修饰,意味着只能初始化一次。
由此引申出关于函数字符串传参的问题。
Java 编程语言只有值传递参数。当一个对象实例作为一个参数被传递到方法中时,参数的值就是该对象的引用的地址。
public static void main(String[] args){
String str1 = "hello";
String str2 = "world";
change(str1, str2);
System.out.println(str1+" "+str2); //输出hello world
}
public static void change(String str1, String str2){
str1 = str2;
str2 = str1+str2;
}
可能很部分人想的不一样,String也是对象,但主函数中的str1,str2却不受影响。
由上所述,函数传递的其实是对象的地址,也就是说将str1和str2两个地址传给了函数内部,无论函数内部的数据如何更改,但主程序中的变量的地址是不变的,而字符串又是不变的,只能初始化一次,因此对于传递字符串变量的函数来说,外部的字符串变量的数据是不会改的。
参考资料:
http://blog.youkuaiyun.com/kingzone_2008/article/details/9220691