java中String字符串的比较和字符串的intern方法
为什么要学习字符串的比较?
在java中,字符串的比较常常用在面试题中,我们很有必要搞懂它
字符串的创建方法
首先我们必须明白两种创建String字符串的方法
String str ="a";
String str = new String("a");
字符串比较的是什么
因为字符串是引用类型,所以"==" 比较字符串比较的是地址。
字符串创建时JVM的执行机制
接着我们要了解创建两种字符串时JVM执行的机制
当我们执行上面一段代码时
str是直接创建,JVM直接将其放进常量池
str1是new创建的,所以JVM会在堆中开辟一个空间,再由堆中的空间指向常量池
我们来看一道例子
public static void main(String[] args) {
String s = "a"; //常量池中没有a 将a 放入 常量池["a"]
String s1 = "b"; //常量池中没有b 将b 放入 常量池["a","b"]
String s2 = "ab"; //常量池中没有ab 将ab 放入 常量池["a","b","ab"]
System.out.println(s2 == s + s1); //f
System.out.println(s2 == "a" + "b"); //t
}
为什么第一个会是false呢?而第二个是true呢?
我们观察两个式子,发现左边的s2都是一样的,那么问题必然出现在右边
第一个式子中右边的s和s1是两个变量
第二个式子右边的"a"和"b"是两个常量
那么,字符串常量和变量的比较会出现什么区别呢?
字符串变量拼接的原理是StringBuilder
字符串常量拼接的原理是编译期优化
对于s+s1 它的拼接原理如下
new StringBuilder.append(a).append(b).tostring 相当于 new string(“ab”)
相当于new了一个"ab" ,s2是直接指向常量池,而s+s1相当于在堆中开辟了新空间,所以地址指向不一样,false
对"a"+“b” 它的拼接原理如下
javac在编译期间的优化 结果已经在编译期间确定为ab,右边是常量相加,编译器就会直接将他们在常量池中拼接起来,s2是直接指向常量池,“a”+"b"也是直接指向常量池,true
字符串的intern方法
intern的方法的解释如下
将这个字符串对象尝试放进常量池,如果该字符串在常量池存在,则不会放入,且返回的值是常量池中的字符串,如果该字符串在常量池中不存在,会把常量池中的字符串对象返回
如何理解这句话呢?
当我们调用String s1 = s.intern方法时,如果常量池中存在了s,那么s的指向地址就不会发生改变,但是其返回值s1是常量池中的字符串,所以s1指向的地址是常量池。 如果常量池中没存在s,那么将s放入常量池中,如果s原来是指向堆中的地址,那么此时s指向的地址就会指向常量池,回值s1是常量池中的字符串,所以s1指向的地址是常量池。
public static void main(String[] args) {
//两个常量放入池中 ["a","b"]
String s = new String("a")+ new String("b");
String s1 = s.intern();
//将s这个字符串放进常量池,如果常量池有,就不会放入,如果没有,就会把串池中的对象返回 常量池中没有"ab" 放入 相当于s就指向常量池的字符串了
//此时常量池 ["a","b","ab"]
System.out.println( s1 == "ab"); //t
System.out.println( s == "ab"); //t
}
我们用两个new创建了s字符串
为什么 s==“ab” 是true呢?按道理来说s是指向堆中的地址,而"ab"是直接指向常量池的?
这就是intern的功劳了
首先我们用new创建了两个字符串常量
此时会把这两个常量放入池中 [“a”,“b”]
当我们调用s.intern方法时
会在常量池中查找是否有和s(“ab”)相同的字符串,结果是没查到,所以就会把s放入到常量池中,此时s就直接指向了常量池中的"ab",所以返回了true
//三个常量放入池中 ["a","b","ab]
String x = "ab";
String s = new String("a")+ new String("b");
String s1 = s.intern(); //将s这个字符串放进常量池,
//如果常量池有,就不会放入,如果没有,就会把串池中的对象返回
System.out.println(x == s); //f
System.out.println(s1 == x); //t
我们创建了三个字符串常量,
此时会把三个常量放入池中 [“a”,“b”,"ab]
当我们调用s.intern方法时
会在常量池中查找是否有和s(“ab”)相同的字符串,结果是查到了,所以就不会将s放入常量池,即s还是指向堆中的地址,而x是直接指向常量池的,所以返回了fasle。
但是其返回值s1是常量池中的字符串,所以s1指向的地址也是常量池,返回true
总结
常量池中的字符串仅是符号,第一次用到时才变为对象
利用串池的机制,来避免重复创建字符串对象
字符串变量拼接的原理是StringBuilder
字符串常量拼接的原理是编译期优化
可以用interin方法,主动将串池中还没有的字符串对象放入串池