当Java中的类不重写hashCode()时, 打印这个类的实例会得到一个很好的唯一编号。

Object的Javadoc说hashCode():

在合理实用的情况下,类Object定义的hashCode方法确实为不同的对象返回不同的整数。

但是当类重写hashCode()时,我如何获得 它唯一的数字?


当前回答

hashCode()和identityHashCode()返回值是不同的。对于两个不相等(用==测试)的对象o1, o2 hashCode()可能是相同的。请看下面的例子。

class SeeDifferences
{
    public static void main(String[] args)
    {
        String s1 = "stackoverflow";
        String s2 = new String("stackoverflow");
        String s3 = "stackoverflow";
        System.out.println(s1.hashCode());
        System.out.println(s2.hashCode());
        System.out.println(s3.hashCode());
        System.out.println(System.identityHashCode(s1));
        System.out.println(System.identityHashCode(s2));
        System.out.println(System.identityHashCode(s3));
        if (s1 == s2)
        {
            System.out.println("s1 and s2 equal");
        } 
        else
        {
            System.out.println("s1 and s2 not equal");
        }
        if (s1 == s3)
        {
            System.out.println("s1 and s3 equal");
        }
        else
        {
            System.out.println("s1 and s3 not equal");
        }
    }
}

其他回答

javadoc for Object指定了这一点

这通常是通过将对象的内部地址转换为整数来实现的,但是JavaTM编程语言并不需要这种实现技术。

如果一个类重写了hashCode,这意味着它想要生成一个特定的id,它将(人们可以希望)具有正确的行为。

你可以使用系统。identityHashCode来获取任何类的id。

如果它是一个可以修改的类,则可以声明一个类变量static java.util.concurrent.atomic.AtomicInteger nextInstanceId。(你必须以明显的方式给它一个初始值。)然后声明一个实例变量int instanceId = nextInstanceId.getAndIncrement()。

hashCode()方法不是用来为对象提供唯一标识符的。它将对象的状态(即成员字段的值)分解为一个整数。这个值主要用于一些基于散列的数据结构,如map和set,以有效地存储和检索对象。

如果需要对象的标识符,我建议您添加自己的方法,而不是重写hashCode。为此,您可以创建如下所示的基接口(或抽象类)。

public interface IdentifiedObject<I> {
    I getId();
}

使用示例:

public class User implements IdentifiedObject<Integer> {
    private Integer studentId;

    public User(Integer studentId) {
        this.studentId = studentId;
    }

    @Override
    public Integer getId() {
        return studentId;
    }
}

我想出了这个解决方案,在我的情况下,我有对象创建在多线程和序列化:

public abstract class ObjBase implements Serializable
    private static final long serialVersionUID = 1L;
    private static final AtomicLong atomicRefId = new AtomicLong();

    // transient field is not serialized
    private transient long refId;

    // default constructor will be called on base class even during deserialization
    public ObjBase() {
       refId = atomicRefId.incrementAndGet()
    }

    public long getRefId() {
        return refId;
    }
}
// looking for that last hex?
org.joda.DateTime@57110da6

如果你在对象上执行.toString()时查看hashcode Java类型,底层代码是这样的:

Integer.toHexString(hashCode())