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


    通常来说,我们认为hashCode不相同就为不同的对象。就这样由一段代码引发了一场讨论,代码如下:

     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在创建对象的特殊性。
    运行上面的代码结果为:

        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过程。

    注意:

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

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

  • 相关阅读:
    基于Adaboost的人脸检测算法
    操作系统笔试题及答案
    eclipse Maven plugin 配置
    网站服务管理系统系列教程之五
    2017第4周日
    2017春节~人生智慧箴言
    2017年初夕
    2017农历二十九
    王国维收藏真伪
    2017第3周二假期里该做的事
  • 原文地址:https://www.cnblogs.com/ben-mario/p/11238191.html
Copyright © 2020-2023  润新知