当toString()和hashCode()被覆盖时,如何获取Java对象的“对象引用”?


106

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

问题在于所讨论的类是从另一个类继承的,该类已经覆盖了toString()和hashCode(),后者通常会给我id。

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


1
取决于您是否可以做到... ==是可行的方法...但是我不知道所讨论的代码是如何构成的。同样,hashCode可能适合您的工作,但是它可能会因实现库的方式而中断。
TofuBeer

这确实是一个好问题。
张翔

Answers:


108

您计划使用它的确切内容(您想做什么与需要调用的内容有所不同)。

hashCode如JavaDocs中所定义,表示:

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

因此,如果您hashCode()要查找它是否是内存中的唯一对象,那么这样做并不是一个好方法。

System.identityHashCode 执行以下操作:

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

对于您正在执行的操作,听起来听起来像您想要的...但是根据库的实现方式,您想要执行的操作可能并不安全。


6
我没有根据代码中的值进行操作。至今 我的问题编辑,在某些情况下我仅将其用于调试目的。这就是为什么我觉得我的答案是合理的,但是我给您+1来提供有见地的答复。
Nicolai

1
它总是可以做您想做的事情-但在某些VM上可能会损坏。
TofuBeer

它会在任何合理的VM上中断(即identityHashCode不一定是唯一的)。identityHashCode不是ID
Tom Hawtin-钉路

如前所述,没有保证哈希码是基于地址的。我已经看到WAS内部的IBM VM中出现了具有相同ID的多个对象。
罗宾

“通常通过将对象的内部地址转换为整数来实现”,不是保证值,而是Sun的默认实现。像s =“ Hello”和t =“ Hello”之类的东西可能会导致s和t具有相同的identityHashCode,因为它们实际上是同一对象。
TofuBeer

50

这是我解决的方法:

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

5
这实际上是不正确的,因为多个对象可以返回相同的identityHashCode。
罗宾

2
具有相同标识哈希的两个对象(引用)是同一对象,不是真的吗?这就是OP想要的
basszero

3
不,那不是真的。这很有可能,但不能保证,因为规范未定义算法。
罗宾(Robin)2013年

8

==不管对象的hashCode或equals实现如何,Double 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。null将返回null。

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

1
如果您使用的是Java 7,则应考虑使用java.util.Objects
noahlz 2012年

5

由于默认的hashCode()可能不会返回地址,因此您无法安全地执行所需的操作,并且已经提到,具有相同hashCode的多个对象是可能的。完成所需操作的唯一方法是实际覆盖有问题的对象的hashCode()方法,并确保它们都提供唯一的值。在您的情况下这是否可行是另一个问题。

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


2

为您的所有实例添加唯一的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扩展并查询此属性。在单个虚拟机内将是安全的(假设没有使用类加载器进行游戏来解决静态问题)。


在这种情况下,我可能会使用AtomicInteger -它具有较高的吞吐量,因为不需要同步,并且使用了由sun.misc.Unsafe
RAnders00 '16

1

我们可以简单地从对象类的tostring复制代码以获取string的引用

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)));
  }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.