Java的String类型,你彻底理解吗?看看下面的题目:
String s=”abc”;
String s1=”abc”;
String s2=new String(“abc”);
String s3=s2.intern();
System.out.println(s1==s);
System.out.println(s1==s2);
System.out.println(s1==s3);
上面的题目会打印什么?
如果你不确定,那么请打开Eclipse,敲入上面的程序运行一下,你会发现打印的是true、false、true,为什么会有上面的打印呢?了解了下面关于java String的细节后,就会明白:
1.双引号字符串是常量字符串,在java文件编译的时候就放在虚拟机的常量池中,比如s,当创建abc时,发现常量池中没有就在常量池中创建abc并把abc的地址赋给s,当再创建s1时,首先会去常量池中去查找abc是否存在,如果存在就把常量池中abc的地址赋给s1,所以比较s和s1的地址是相等的
2.如果用new的方法创建一个String时,就和s=”abc”不一样了,s2=new String(“abc”)是在程序运行时创建,不是创建在常量池而是和其他java对象一样在java堆上创建,因此它的地址和s不用.
3.如果运行时想把一个String创建到常量池中,java提供了一种方法,这个方法也会先检查常量池是否存在abc,若存在返回abc在池中的地址。所以最后一个打印时true
在看下面的题目:
String s1=”ab”;
String s2=”cd”;
String s3=”abcd”;
String s4=s1+s2;
String s5=”ab”+"cd”;
System.out.println(s4==s3);
System.out.println(s5==s3);
这是又会是什么结果呢?答案是false,true,这个题目说明两个字符串常量连接和还是字符串常量,但是只要其中一个是变量,就和new的效果一样了,即是在堆上创建
说完了java的String类型,我们最后看看java函数参数的传递,到底是值传递还是引用传递呢?一般的说法是对于基本类型比如int、char是值传递,对于对象类型是引用传递。这种说法没错,但是请看下面的例子:
String s=”abc”;
change(s);
System.out.println(s);
public void change(String str)
{
str=”abcd”;
}
上面的程序会有什么结果呢?打印abc还是abcd,运行程序会发现打印的是abc,完了,似乎不合乎常理,按理说String 也是对象,应该是引用传递才对啊,有的同学知道java的String类型是不可变类型,会得出结果abc,具体解释是String就相当于是char[]的包装类。包装类的特质之一就是在对其值进行操作时会体现出其对应的基本类型的性质。在参数传递时,包装类就是如此体现的。所以,对于String在这种情况下的展现结果的解释就自然而然得出了。同样的,Integer、Float等这些包装类和String在这种情况下的表现是相同的。下面从函数参数传递的方式来理解也可以得出相同的结果。
java的参数传递本质上都可以认为是值传递,对基本类型自然不必说,对于对象类型,传递的是对象的地址,地址是个数字,也是基本类型,所以也还是值传递的, 有了这个基础,上面的题目可以这样理解,s是字符串abc的地址,调用change方法时,把s的拷贝赋给str,即str也指向abc,但是在方法里又把str指向abcd,str就是abcd的地址了,但是s还是指向的abc。