首先声明一点,在Java 编程语言只有值传递参数,而没有引用传递。
昨天有人给我讲java中的值传递和引用传递,理所当然的我就说基本类型是引用传递,对象类型的是引用传递,那个人还问了好多次,你确定么,我坚定的回答,肯定是这样的。后来写了几个demo,才发现以前对这些基本知识都没有深刻的认识。如果这是一次面试,听了这样的回答,面试官会果断的不要我。
在这之前先讲一个基本知识点,java中有 ==和equals两个比较方法,大概的意思是==比较的是两个对象的地址,即句柄,equals继承了Object类,比较的是两个对象的内容。对象有一个hashCode()的方法,其实是对其进行hash,具体的算法不说,大概的意思就是取其物理地址。
下面来看几个神奇的demo:
1、
public static void main(String[] args) {
String str = "old";
System.out.println(str);
change(str);
System.out.println(str);
}
public static void change(String str){
str = "newString";
}
当我认为运行结果理所当然的是
old
newString 的时候
正确的运行结果却是:
old
old
原因可以这样理解,其实change方法中给传递的是对象引用的拷贝,但是俩指向的都是同一个对象,但是上面的change方法,把引用的拷贝指向了一个新的对象“newString”,而真实的依然是指向“old”这个对象,因此主函数中调用方法以后对象值仍然不变。
再来看一个demo2:
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("old");
System.out.println(sb.toString());
System.out.println(sb.hashCode());
change2(sb);
System.out.println(sb.toString());
System.out.println(sb.hashCode());
}
public static void change2(StringBuilder sb){
sb = new StringBuilder("New String");
sb.append("append");
System.out.println(sb.toString());
System.out.println(sb.hashCode());
}
执行结果如下:
old
1396452035
New Stringappend
320574182
old
1396452035
demo3代码以及运行结果如下:
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("old");
System.out.println(sb.toString());
System.out.println(sb.hashCode());
change2(sb);
System.out.println(sb.toString());
System.out.println(sb.hashCode());
}
public static void change2(StringBuilder sb){
sb.append("append");
System.out.println(sb.toString());
System.out.println(sb.hashCode());
}
old
1441188650
oldappend
1441188650
oldappend
1441188650
由上两个代码可以得出,由于传递的对象的引用的拷贝和对象的引用指向的是同一对象,当对对象的值进行操作的时候,真实的引用指向的对象也会改变。但是当拷贝指向新的对象以后,原来的引用指向的对象依旧是原来的那个不会改变。
另外额外再补充一点:
String类是一个非常特殊的类:
String类是不可变的,对String类的任何改变,都是返回一个新的String类对象,因此尽管你对String的值进行了改变,但事实上是返回了一个新的对象。
比如下面的一段代码,可以看到str的真实值没有改变,因为String的subString方法返回的也是一个新的字符串对象。
public static void main(String[] args) {
String str = "idontknow";
System.out.println(str);
change1(str);
System.out.println(str);
}
public static void change3(String str){
str = str.substring(2,str.length());
System.out.println(str);
}
idontknow
ontknow
idontknow
值得注意的是当使用
String str="abc"+"de";
这样一段代码的时候,由于String的对象是一个常量,会放到String常量池中,因此会占用资源,所以,经常会使用StringBuffer来构建字符串然后再将其转化成String.