【问题标题】:How do you get the "object reference" of an object in java when toString() and hashCode() have been overridden?当 toString() 和 hashCode() 被覆盖时,如何在 java 中获取对象的“对象引用”?
【发布时间】:2010-10-09 12:30:26
【问题描述】:

我想在 Java 中打印对象的“对象引用”以进行调试。 IE。根据情况确保对象相同(或不同)。

问题是有问题的类继承自另一个类,它覆盖了 toString() 和 hashCode() 这通常会给我 id。

示例情况: 运行一个多线程应用程序,我(在开发期间)想要检查所有线程是否使用资源对象的同一个实例。

【问题讨论】:

  • 取决于你是否可以做到... == 是要走的路...但我不知道有问题的代码是如何构造的。同样,hashCode 可能适合您正在做的事情,但它可能会根据库的实现方式而中断。
  • 这真是个好问题。

标签: java object hashcode


【解决方案1】:

我就是这样解决的:

Integer.toHexString(System.identityHashCode(object));

【讨论】:

  • 这实际上是不正确的,因为多个对象可以返回相同的identityHashCode。
  • 具有相同标识哈希的两个对象(引用)不是同一个对象吗?这就是 OP 想要的
  • 不,这不是真的。很有可能,但不能保证,因为规范没有定义算法。
【解决方案2】:

您究竟打算用它做什么(您想要做什么与您需要调用的内容不同)。

hashCode,如 JavaDocs 中所定义,说:

在合理可行的情况下,由 Object 类定义的 hashCode 方法确实为不同的对象返回不同的整数。 (这通常通过将对象的内部地址转换为整数来实现,但 Java™ 编程语言不需要这种实现技术。)

因此,如果您使用hashCode() 来确定它是否是内存中的唯一对象,那么这不是一个好方法。

System.identityHashCode 执行以下操作:

无论给定对象的类是否覆盖 hashCode(),返回给定对象的哈希码与默认方法 hashCode() 返回的哈希码相同。空引用的哈希码为零。

就您所做的而言,这听起来像是您想要的……但您想要做的事情可能并不安全,具体取决于库的实现方式。

【讨论】:

  • 我没有对代码中的值采取行动。作为公关。我的问题编辑,我只将它用于特定情况的调试目的。这就是为什么我觉得我的回答是合理的,但我给你一个 +1 的有见地的答复。
  • 很可能它总是会做你想做的事 - 但它可能会在某些虚拟机上中断。
  • 它会在任何合理的 VM 上中断(即 identityHashCode 不一定是唯一的)。 identityHashCode 不是 I.D.
  • 如前所述,没有基于地址的哈希码的保证。我在 WAS 内部的 IBM VM 中看到了多个具有相同 ID 的对象。
  • “这通常通过将对象的内部地址转换为整数来实现”不是保证,而是 Sun 的默认实现。像 s = "Hello" 和 t = "Hello" 这样的事情可能会导致 s 和 t 具有相同的 identityHashCode,因为它们实际上是同一个对象。
【解决方案3】:

你不能安全地做你想做的事,因为默认的 hashCode() 可能不会返回地址,并且已经提到,具有相同 hashCode 的多个对象是可能的。完成您想要的唯一方法是实际覆盖所讨论对象的 hashCode() 方法并保证它们都提供唯一值。这在您的情况下是否可行是另一个问题。

作为记录,我在 WAS 服务器中运行的 IBM VM 中遇到了多个具有相同默认哈希码的对象。我们有一个缺陷,即被放入远程缓存的对象会因此而被覆盖。这让我大开眼界,因为我认为默认哈希码也是对象的内存地址。

【讨论】:

    【解决方案4】:

    为所有实例添加一个唯一的 ID,即

    public interface Idable {
      int id();
    }
    
    public class IdGenerator {
      private static int id = 0;
      public static synchronized int generate() { return id++; }
    }
    
    public abstract class AbstractSomething implements Idable {
      private int id;
      public AbstractSomething () {
        this.id = IdGenerator.generate();
      }
      public int id() { return id; }
    }
    

    从 AbstractSomething 扩展并查询此属性。在单个 vm 中是安全的(假设没有使用类加载器玩游戏来绕过静态)。

    【讨论】:

    • 我可能会在这种情况下使用 AtomicInteger - 它具有更高的吞吐量,因为不需要同步并且它使用由sun.misc.Unsafe提供的本机原子内存操作
    【解决方案5】:

    双等号== 将始终根据对象身份进行检查,而不管对象的 hashCode 或 equals 实现如何。当然 - 确保您正在比较的对象引用是 volatile(在 1.5+ JVM 中)。

    如果您确实必须拥有原始 Object toString 结果(尽管它不是您的示例用例的最佳解决方案),Commons Lang 库有一个方法 ObjectUtils.identityToString(Object) 可以满足您的需求。来自 JavaDoc:

    public static java.lang.String identityToString(java.lang.Object object)
    

    获取将是的 toString 如果一个类没有,则由 Object 产生 覆盖 toString 本身。空意志 返回空值。

     ObjectUtils.identityToString(null)         = null
     ObjectUtils.identityToString("")           = "java.lang.String@1e23"
     ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"
    

    【讨论】:

    • 如果你使用的是Java 7,那么你应该考虑使用java.util.Objects
    • 关于您的评论,您想到了java.util.Objects 中的哪些方法? Objects.toString(o) 相当于调用 o.toString(),带有 null 检查,这似乎与这个问题无关。
    • @amaidment 好的,是的,Object.toString 只是在引用上调用 toString,避免 NPE
    【解决方案6】:

    我们可以简单地从对象类的tostring中复制代码来获得 字符串的引用

    class Test
    {
      public static void main(String args[])
      {
        String a="nikhil";     // it stores in String constant pool
        String s=new String("nikhil");    //with new stores in heap
        System.out.println(Integer.toHexString(System.identityHashCode(a)));
        System.out.println(Integer.toHexString(System.identityHashCode(s)));
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-06-02
      • 2010-10-28
      • 1970-01-01
      • 1970-01-01
      • 2020-02-19
      • 2013-04-13
      • 2017-03-26
      • 1970-01-01
      • 2015-07-08
      相关资源
      最近更新 更多