如果在池中创建字符串,如何确认(或获取字符串的对象重复)?

时间:2015-10-10 18:30:31

标签: java string object immutability pool

我想确认创建的两个String变量是否指向同一个内存。我用普通类做的方式

Ideone a=new Ideone();
Ideone b=a;

System.out.println(a+" "+b);

输出

Ideone@106d69c Ideone@106d69c

这里产生的输出不是确切的内存地址,但它给出了相同的十六进制代码,我可以说它们都指向相同的内存地址或值。

但是在String

的情况下
String a="helloworld";
String b="hello";
String c=b+"world";
System.out.println(a+" "+c);

输出

helloworld helloworld

它是预期的输出,我知道在池中创建了a,b,c,因为它们是编译时常量而ac没有指向相同的内存。但是有没有什么方法可以获得像String@23122这样的字符串的Object表示,以获取该对象的十六进制代码,以确认ac没有指向同一个内存?< /强> 因为在new String("helloworld")创建字符串的情况下,新内存被分配给字符串。

我搜索了它,但是找到了与我的问题类似的东西。

提前致谢。

3 个答案:

答案 0 :(得分:2)

正如JLS

中所述
  

字符串文字始终引用类String的相同实例。

但是,它也取决于你如何形成String对象。
示例:调用new String("abcd")就像拥有字符串参数“abcd”,但仍然强制JVM创建一个新的String引用。查看更多信息部分...

正如您在示例中所说,您无法获取指针ID,但仍然可以通过调用toString()方法获得一些唯一字符串,使用它可以使它们符合它们的唯一性。但是toString的实现是Object.toString()

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

所以,它是 HashCode

根据Hashcode契约,如果两个对象相等,那么这意味着它们的hashCode必须相同,但不是真的,反之亦然。

来自spec的hashCode的一般合约是:

  
      
  • 每当在同一个对象上多次调用它时   执行Java应用程序时,hashCode方法必须始终如一   返回相同的整数,前提是equals中没有使用的信息   对象的比较被修改。不需要保留该整数   从一个应用程序的执行到另一个执行的一致性   相同的申请。

  •   
  • 如果两个物体相等则   equals(Object)方法,然后在每个上调用hashCode方法   两个对象必须产生相同的整数结果。

  •   
  • 不需要   如果两个对象根据不相等而不相等   equals(java.lang.Object)方法,然后调用hashCode方法   两个对象中的每一个都必须产生不同的整数结果。   但是,程序员应该意识到产生了不同的   不等对象的整数结果可以提高性能   哈希表。

  •   

因此,要么使用==运算符进行身份/引用检查,要么必须信任JVM实现,String文字始终指向唯一引用,否则JVM不遵循规范。

更多信息:

这是上面提到的JLS规范中给出的例子。

package testPackage;
class Test {
    public static void main(String[] args) {
        String hello = "Hello", lo = "lo";
        System.out.print((hello == "Hello") + " ");
        System.out.print((Other.hello == hello) + " ");
        System.out.print((other.Other.hello == hello) + " ");
        System.out.print((hello == ("Hel"+"lo")) + " ");
        System.out.print((hello == ("Hel"+lo)) + " ");
        System.out.println(hello == ("Hel"+lo).intern());
    }
}

class Other { static String hello = "Hello"; }

和编译单元:

package other;
public class Other { public static String hello = "Hello"; }

产生输出:

  

true true true true false true

这个例子说明了六点:

  • 同一个包中同一个类中的文字字符串表示对同一个String对象的引用。

  • 同一个包中不同类中的文字字符串表示对同一个String对象的引用。

  • 不同包中不同类中的文字字符串同样表示对同一String对象的引用。

  • 由常量表达式计算的字符串在编译时计算,然后视为文字。

  • 在运行时通过串联计算的字符串是新创建的,因此是不同的。

  • 显式实习计算字符串的结果与具有相同内容的任何预先存在的文字字符串相同。

答案 1 :(得分:1)

  

我想确认创建的两个String变量是否指向同一个内存

您可以使用==运算符检查是否有任何对象引用指向同一对象。这就是你所需要的:

boolean sameObject = (a == b);
  

有什么办法可以像String @ 23122

那样得到字符串的Object表示

是的,如果你真的想要那个:

System.out.println(a.getClass().getName() + "@" + Integer.toHexString(System.identityHashCode(a)));

但这不会有用,因为两个不同的对象可能具有相同的哈希码。哈希码不一定是内存地址,usually isn't

答案 2 :(得分:1)

首先,你的方法是错误的。您指望的是未覆盖toString() Object方法的类的字符串表示形式。

如果未覆盖Object.toString方法,则返回一个字符串,该字符串由类的名称@和对象的哈希码组成。这不是它的地址,它与地址无关。因此,具有相同哈希码的两个对象将返回相同的字符串。

为了证明这一点,让我们看一个覆盖equalshashCode的小类,但不会覆盖toString方法:

class MyInteger {
    int myInteger;

    public MyInteger(int myInteger) {
        this.myInteger = myInteger;
    }

    public int getInteger() {
        return myInteger;
    }
    @Override
    public boolean equals(Object obj) {
        if ( obj instanceof MyInteger ) {
            return myInteger == ((MyInteger)obj).myInteger;
        }
        return false;
    }

    @Override
    public int hashCode() {
        return myInteger;
    }
}

现在,让我们尝试区分两个不同对象的方法:

MyInteger int1 = new MyInteger(1004);
MyInteger int2 = new MyInteger(1004);
System.out.println(int1+" "+int2);

打印结果如下:

MyInteger@3ec MyInteger@3ec

但显然int1int2指向两个不同的对象,使用new明确创建!

所以忘记那个方法 - 它没有意义。

现在,你怎么知道两个对象是截然不同的?很简单,请将参考文献与==!=进行比较。

所以,如果我在上面试过

System.out.println( int1 != int2 );

结果为true

字符串也一样:

String a="helloworld";
String b="hello";
String c=b+"world";
String d="hello";
System.out.println("a refers to a different object than c? " + (a != c));
System.out.println("b refers to a different object than d? " + (b != d));

打印的结果将是:

a refers to a different object than c? true
b refers to a different object than d? false