String型变量的定义与引用
大家都在讲, 在Java中,变量是按引用传递,除了基本数据类型和String。基本数据类型没有什么可讲的,那么String到底有什么特殊的地方。
提到String,就得提StringBuffer,下面通过几个例子来说明他们的区别。
public class Test {
public static void main(String[] args) {
String A="aaa";
String B="bbb";
System.out.println(A.equals(B));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
B=A;
System.out.println(A.toString().equals(B.toString()));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
}
}
输出结果为:
false
false
96321
97314
true
true
96321
96321
大家都应该能预测到这个结果,因为我们把A赋值给了B。
让我们稍微改动一下,用B="aaa"代替B=A。
public class Test {
public static void main(String[] args) {
String A="aaa";
String B="bbb";
System.out.println(A.equals(B));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
B="aaa";
System.out.println(A.toString().equals(B.toString()));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
}
}
再来看输出结果,
false
false
96321
97314
true
true
96321
96321
有些想不到吧,和B=A是一样的。再做一下改动,把B="aaa"改成B="aa“+”a",
public class Test {
public static void main(String[] args) {
String A="aaa";
String B="bbb";
System.out.println(A.equals(B));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
B="aa"+"a";
System.out.println(A.toString().equals(B.toString()));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
}
}
结果仍然是,
false
false
96321
97314
true
true
96321
96321
看到了吧,这就是String和其他对象类型不一样的地方。不管你怎么定义或赋值,只要字符串变量的内容是相同的,他们指向的就是同一个字符串对象。
比如上面的例子,不管B的值是从A赋过来的,还是自己定义的,只要他的值是‘aaa’,他和A指向的就是同一个对象。
这样做的好处嘛,我只想到一点儿,节省资源。比如你有10个变量的值都是'aaa',那么这10个变量指向的是同一个对象,而不是10个对象。
再来看看StringBuffer,差不多的一个例子,
public class Test {
public static void main(String[] args) {
StringBuffer A=new StringBuffer("aaa");
StringBuffer B=new StringBuffer("bbb");
System.out.println(A.equals(B));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
B=A;
System.out.println(A.toString().equals(B.toString()));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
}
}
输出结果,
false
false
3526198
7699183
true
true
3526198
3526198
稍微改动一下,B=A替换为B=new StringBuffer("aaa"),
public class Test {
public static void main(String[] args) {
//(Man.getMan()).printName();
//System.out.println((Man.getMan()));
StringBuffer A=new StringBuffer("aaa");
StringBuffer B=new StringBuffer("bbb");
System.out.println(A.equals(B));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
B=new StringBuffer("aaa");
System.out.println(A.toString().equals(B.toString()));
System.out.println(A==B);
System.out.println(A.hashCode());
System.out.println(B.hashCode());
}
}
输出结果为,
false
false
3526198
7699183
true
false
3526198
14285251
怎么样,看到StringBuffer和String是不一样的啦吧,虽然A和B的值相同,但是指向的是不同的对象。StringBuffer和其他对象类型一样,是按引用传递的。
String和StringBuffer的其他区别:
1. StirngBuffer是可以变话的,如果改变了StringBuffer变量的长度或内容,不会改变对这个对象的引用。
2. String是固定的,如果改变了String变量的长度或内容,就会新建一个String对象,原来的String变量会指向新的String对象。
下面是根据‘会飞的鱼’网友的建议做的补充,
因为在 java 中 String 是一个非常特殊的对象,在内存在存在一个String pool 的内存池,用于保存String 常量,而采用 new 关键字进行生成的对象,是保存在堆中的。这两个是不一样的。
public class StringTest {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
String s = new String("abc");
String s1= "abc"; String s2 = new String("abc");
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s==s1); ///输出值是什么? ---false
System.out.println(s==s2); ///输出值是什么? ---false
System.out.println(s1==s2); ///输出值是什么? ---false
== 两边判断的是引用的地址是否一样。
String hello = "hello";
String hel = "hel";
String lo = "lo";
System.out.println(hello.hashCode());
System.out.println(("hel"+lo).hashCode());
System.out.println(hello=="hel"+"lo"); ///输出值是什么? ----true
System.out.println(hello=="hel"+lo); ///输出值是什么? --- false
}
}
输出结果为:
96354
96354
96354
false
false
false
99162322
99162322
true
false
补充总结:
1. 使用new 关键字生成的对象,是保存在堆中的。每使用一次new,就会生成一个新的引用对象(分配新的内存地址)。
2. 使用new和直接赋值生成的String对象的引用地址是不用的,即使他们的hashcode相同。
3. == 两边判断的是引用的地址,而不是hashcode。
4. Object.hashcode()方法返回的是内存地址,但是String类改写了hashcode()方法。所以String对象的hashcode值并不是内存地址。