关于一段有趣代码引出的String建立对象的解释

一般来讲,咱们认为hashCode不相同就为不一样的对象。就这样由一段代码引起了一场讨论,代码以下:spa

 1     @Test
 2     public void stringCompare() {
 3         String s1 = "test";
 4         String s2 = "test";
 5         String s3 = new String("test");
 6         String s4 = new String("test");
 7 
 8         System.out.println("value compare:");
 9         System.out.println("s1.equals(s2):" + s1.equals(s2));
10         System.out.println("s2.equals(s3):" + s2.equals(s3));
11         System.out.println("s3.equals(s4):" + s3.equals(s4));
12         System.out.println("s1==s2:" + (s1 == s2));
13         System.out.println("s2==s3:" + (s2 == s3));
14         System.out.println("s3==s4:" + (s3 == s4));
15 
16         System.out.println("hashCode compare:");
17         System.out.println("s1~s2:"+ (s1.hashCode() == s2.hashCode()));
18         System.out.println("s2~s3:"+ (s2.hashCode() == s3.hashCode()));
19         System.out.println("s3~s4:"+ (s3.hashCode() == s4.hashCode()));
20     }


有兴趣的话先猜一猜上面的打印结果。这段代码能够很好的说明String在建立对象的特殊性。
运行上面的代码结果为:code

    value compare:
    s1.equals(s2):true
    s2.equals(s3):true
    s3.equals(s4):true
    s1==s2:true
    s2==s3:false
    s3==s4:false
    hashCode compare:
    s1~s2:true
    s2~s3:true
    s3~s4:true


猜对了吗?会不会有点奇怪,接下来我将逐一说明,并解释String建立对象的机理。

首先咱们知道equals的比较是两个对象的值是否相同,这个毋庸置疑,咱们都赋值“test”,因此结果必然是三个true,这一点没有什么问题。

而后看“==”的比较,“==”是比较物理地址时候相同,也是比较是否为同一对象的手段。结果是s1和s2是true,后面的两个比较是false,这就说明s1和s2指向的是同一块地址。s3和s4是经过new出来的对象,咱们知道new一般是开辟了新空间,而直接赋值是引用赋值。因此这一点也基本上没有什么问题,这就解释了s2==s3:false,s3==s4:false。

最后同一般咱们认为hashCode不一样就是不一样的对象,可是这四个对象的hashCode是所有相同的。这彷佛和使用"=="比较有点违背。但其实并不矛盾,必须明确一点是hashCode和物理地址没有必然的关系。之因此是这样,是由于Sting在建立对象时的机制有所不一样。

重点:
    JVM为String类型提供了一个字符池(jdk7以前在permgen,jdk7以后也是堆里)。每次在建立对象时,都会如今字符池中查找该字符串是否存在。这是大的前提逻辑,如今咱们就一下几种状况分别说明:对象

1.建立一个对象 String s1 = new String("我是字符串"),遵循大逻辑,先在pool中检索,但其实不管pool中有没有,都会建立一个新的对象。不一样的是:
    a.pool中没有:
        在pool中添加一个新的对象“我是字符串”,也就是说这里建立了两个对象,除了s1这个对象外,在pool中还建立了一个对象;这个时候建立s2 = "我是字符串"; 一样检查pool,发现已有,那s2指向pool中的“我是字符串”的地址。
    b.pool中有:
        则只建立一个对象及就是s1。这个时候建立s2= “我是字符串”;一样会检查pool发现存在,那s2直接指向pool中的地址。
2.建立一个String s1 = "我是字符串",遵循大逻辑,先在pool中检索:
    a.pool中没有:
        在pool中没有检索到“我是字符串”,那么在pool中添加一个字符串对象“我是字符串”,而后s1指向pool中的地址。这个时候若是建立String s2 = new String("我是字符串");检测pool中已有,同1.b中建立s1过程。
    b.pool中有:
        在pool中检索到,s1直接指向pool中的地址,若是建立String s2 = new String("我是字符串");同1.b中建立s1过程。blog

注意:字符串

  1.hashCode实际与物理地址没有必然关系,只是习惯上咱们能够用hashCode判断是否为同一对象。string

  2.pool也是有大小限制的,对于不用的字符串对象,垃圾机器人会回收,释放空间。hash

相关文章
相关标签/搜索