如果字符串是否在池中创建,如何确认(或获取字符串的对象表示)?

How to confirm( or get the object repesentation of string) if string created in pool or not?

我想确认创建的两个 String 变量是否指向相同的 memory.The 方式,我用正常方式 class

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 这样的字符串的对象表示来获取该对象的十六进制代码以确认 ac 不指向相同的内存? 因为万一通过 new String("helloworld") 创建字符串,新内存将分配给字符串。

我已经搜索过了,但没有找到任何与我的问题类似的东西。

提前致谢。

JLS

中所述

A string literal always refers to the same instance of class String.

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

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

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

因此,它是HashCode

根据 Hashcode 合约,如果两个对象相等,则意味着它们的 hashCode 必须相同,但反之则不然。

来自spec的hashCode的总契约是:

  • Whenever it is invoked on the same object more than once during an execution of a Java application, the hashCode method must consistently return the same integer, provided no information used in equals comparisons on the object is modified. This integer need not remain consistent from one execution of an application to another execution of the same application.

  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.

  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

因此,要么使用 == 运算符进行 identity/reference 检查,要么您必须信任 JVM 实现,字符串文字始终指向唯一引用,否则 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

这个例子说明了六点:

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

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

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

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

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

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

I want to confirm if two String variable created is pointing to the same memory

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

boolean sameObject = (a == b);

is there any way I can get the Object representation of string like String@23122

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

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

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

首先,你的方法是错误的。您指望 classes 的字符串表示形式尚未覆盖 Object.

中的 toString() 方法

Object.toString 方法,如果未被覆盖,return 是一个由 class、@ 的名称组成的字符串对象的哈希码。不是它的地址,跟地址没有关系。因此,具有相同哈希码的两个对象将 return 相同的字符串。

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

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