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方法,主动将串池中还没有的字符串对象放入串池

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值