【问题标题】:How to confirm( or get the object repesentation of string) if string created in pool or not?如果字符串是否在池中创建,如何确认(或获取字符串的对象表示)?
【发布时间】:2015-10-10 18:30:30
【问题描述】:

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

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

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

输出

Ideone@106d69c Ideone@106d69c

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

但是在字符串的情况下

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")创建字符串的情况下,新内存被分配给字符串。

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

提前致谢。

【问题讨论】:

    标签: java string object immutability pool


    【解决方案1】:

    JLS 中所述

    字符串字面量总是指代 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的通用合约是:

    • 每当在同一对象上多次调用它时 执行 Java 应用程序时,hashCode 方法必须一致 返回相同的整数,只要不使用 equals 中的信息 对象上的比较被修改。这个整数不需要保留 从应用程序的一次执行到另一次执行一致 相同的应用程序。

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

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

    因此,要么使用== 运算符进行身份/引用检查,要么您必须信任字符串文字始终指向唯一引用的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"; }
    

    产生输出:

    真真真真真

    这个例子说明了六点:

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

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

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

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

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

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

    【讨论】:

    • 我很困惑选择哪个答案,因为它们都很好,但我喜欢你的答案除了其他的是你 hashCose javaspecs.Thanks
    【解决方案2】:

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

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

    boolean sameObject = (a == b);
    

    有什么办法可以得到像 String@23122 这样的字符串的对象表示

    是的,如果你真的想要的话:

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

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

    【讨论】:

    • 但是,'在合理可行的情况下,由 Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。'
    • 我太愚蠢了,我记得== 用于参考检查:)
    【解决方案3】:

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

    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);
    

    打印出来的结果是这样的:

    我的整数@3ec 我的整数@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 指的是与 c 不同的对象?真的
    b 指的是与 d 不同的对象?假的

    【讨论】:

      猜你喜欢
      • 2022-06-29
      • 2021-01-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多