当Java中的类不重写hashCode()时, 打印这个类的实例会得到一个很好的唯一编号。
Object的Javadoc说hashCode():
在合理实用的情况下,类Object定义的hashCode方法确实为不同的对象返回不同的整数。
但是当类重写hashCode()时,我如何获得 它唯一的数字?
当Java中的类不重写hashCode()时, 打印这个类的实例会得到一个很好的唯一编号。
Object的Javadoc说hashCode():
在合理实用的情况下,类Object定义的hashCode方法确实为不同的对象返回不同的整数。
但是当类重写hashCode()时,我如何获得 它唯一的数字?
当前回答
只是从另一个角度扩大其他答案。
如果你想重用来自“上面”的hashcode,并使用类的“不可变状态”派生新的hashcode,那么调用super就可以了。虽然这可能会/可能不会一直级联到Object(即某些祖先可能不会调用super),但它将允许您通过重用派生哈希码。
@Override
public int hashCode() {
int ancestorHash = super.hashCode();
// now derive new hash from ancestorHash plus immutable instance vars (id fields)
}
其他回答
也许这个快速,肮脏的解决方案会起作用?
public class A {
static int UNIQUE_ID = 0;
int uid = ++UNIQUE_ID;
public int hashCode() {
return uid;
}
}
这也给出了被初始化的类的实例数。
如果它是一个可以修改的类,则可以声明一个类变量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;
}
}
// looking for that last hex?
org.joda.DateTime@57110da6
如果你在对象上执行.toString()时查看hashcode Java类型,底层代码是这样的:
Integer.toHexString(hashCode())
我想出了这个解决方案,在我的情况下,我有对象创建在多线程和序列化:
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;
}
}