Java String类的一些细节总结

本文主要介绍String类中的value成员变量和intern()方法以及==equals()方法的区别。

value成员变量

再介绍这个成员变量之前,我想先讲一下为什么Java要引入常量池这个概念。

我们指的每次创建字符串,都需要分配一段内存空间,假如说我们将相同内容的字符串包含到了程序的不同地方,那么就造成了内存浪费,这个时候自然而然我们希望每次创建一个字符串都保存起来,以后再有需要相同字符串的地方,就复用这个保存好的字符串的引用就行了。总而言之,常量池的目的就是为了节约内存。

那么value就是用来做这件事的,它存储的就是字符串所包含的内容。当创建一个String对象时,传入的字面量的引用就作为value的值。

这个字面量首先会去常量池里面找,找得到就返回常量池对应的字符串的引用,找不到就在常量池新建一个字符串再返回其引用。

但是value也不总是是一个常量池中字符串的引用,比如:

String str = new String("ab") + new String("c");

对象strvalue存的值就不会是常量池中字符串的值,因为这是两个变量相加,无法在编译时唯一确定。至于为什么说编译时无法确定就不行,请看下面这个例子:

public class MyTest {
    
    
    static final String a = "ab";
    static final String b = "c";
    public static void main(String[] args) {
    
    
        String c = a + b;
        System.out.println(c == "abc");
    }
}

这段代码将输出true,如果把final删掉,则变为false这其实也说明了如果能在编译时唯一确定,那么在编译为.class文件这个过程中编译器会做对应的优化。

其实不仅是上面这种情况会做优化,对于字符串常量相加:

String str= "ab" + "cd" + "ef";

会变成

String str= "abcdef";

对于字符串变量相加:

String str = "abcdef"; 

for(int i=0; i<1000; i++) {
    
     
  str = str + i; 
} 

会变成

String str = "abcdef"; 

for(int i=0; i<1000; i++) {
    
     
  str = (new StringBuilder(String.valueOf(str))).append(i).toString(); 
} 

除了上述这些之外,其实我们写代码时写下的字面字符串常量,比如"abc",会在编译期间会被优化为一个String对象。具体来说,如果多个字面字符串常量的值相同,编译器会将它们合并为同一个String对象,并在类的常量池中生成对应的常量引用。

intern()方法

JDK7前后的intern()方法在底层实现上不同了,该方法用来返回字符串在常量池中的引用。

intern()方法签名:public native String intern()();

JDK7以前

当通过String构造函数创建一个字符串对象时,intern()方法首先会在常量池中是否有对应的字符串常量,如果没有,就复制一份到常量池,然后返回常量池中复制得到的字符串的引用

JDK7以后

如果常量池中没有,那么只会在常量池中记录该String对象的引用,并不会再在常量池中复制一份字符串常量。

参考链接:从java.lang.String#intern说起JDK6之前和JDK7及之后关于字符串常量池的区别

#==equals()方法的区别
有了以上基础,接下来理解这两者的区别会简单很多。

对于复杂类型的数据,==其实就是比较其二者的hash code。

默认hash code生成貌似是根据对象的内存地址。

所以new String("abc")"abc"并不相等,因为它们根本上来说并不是同一对象,但很明显我们一般认为只要字符串内容一样就算做同一对象,所以这个时候就应该重写equals()方法来判断是否相等,但这个需求由于过于常见,Java已经帮我们做了——重写equals()方法。

这个其实也就是那个老生常谈的问题——为什么重写hashCode()方法就一定要重新equals()方法。

这是因为重写hashCode()方法后,以后集合之类的API就按这个来判断对象是否相等,但我们知道hash函数总是难免发生碰撞,所以不同对象可能也会发生计算出来的hash code相等,这个时候如果我们没有重写equals()方法,那么基本上百分百就会出问题。

因为默认equals()方法是按内存地址来判断两对象是否相等的,那么肯定不会相等,因为我们认为Person p1 = new Person("小明");Person p2 = new Person("小明");是同一个对象,即使我们确实创建的是两个对象。

猜你喜欢

转载自blog.csdn.net/weixin_55658418/article/details/130452547
今日推荐