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;
}
}
@Override
public int hashCode() {
int ancestorHash = super.hashCode();
// now derive new hash from ancestorHash plus immutable instance vars (id fields)
}
import java.util.HashMap;
import java.util.Map;
/**
* Utility for assigning a unique ID to objects and fetching objects given
* a specified ID
*/
public class ObjectIDBank {
/**Singleton instance*/
private static ObjectIDBank instance;
/**Counting value to ensure unique incrementing IDs*/
private long nextId = 1;
/** Map from ObjectEntry to the objects corresponding ID*/
private Map<ObjectEntry, Long> ids = new HashMap<ObjectEntry, Long>();
/** Map from assigned IDs to their corresponding objects */
private Map<Long, Object> objects = new HashMap<Long, Object>();
/**Private constructor to ensure it is only instantiated by the singleton pattern*/
private ObjectIDBank(){}
/**Fetches the singleton instance of ObjectIDBank */
public static ObjectIDBank instance() {
if(instance == null)
instance = new ObjectIDBank();
return instance;
}
/** Fetches a unique ID for the specified object. If this method is called multiple
* times with the same object, it is guaranteed to return the same value. It is also guaranteed
* to never return the same value for different object instances (until we run out of IDs that can
* be represented by a long of course)
* @param obj The object instance for which we want to fetch an ID
* @return Non zero unique ID or 0 if obj == null
*/
public long getId(Object obj) {
if(obj == null)
return 0;
ObjectEntry objEntry = new ObjectEntry(obj);
if(!ids.containsKey(objEntry)) {
ids.put(objEntry, nextId);
objects.put(nextId++, obj);
}
return ids.get(objEntry);
}
/**
* Fetches the object that has been assigned the specified ID, or null if no object is
* assigned the given id
* @param id Id of the object
* @return The corresponding object or null
*/
public Object getObject(long id) {
return objects.get(id);
}
/**
* Wrapper around an Object used as the key for the ids map. The wrapper is needed to
* ensure that the equals method only returns true if the two objects are the same instance
* and to ensure that the hash code is always the same for the same instance.
*/
private class ObjectEntry {
private Object obj;
/** Instantiates an ObjectEntry wrapper around the specified object*/
public ObjectEntry(Object obj) {
this.obj = obj;
}
/** Returns true if and only if the objects contained in this wrapper and the other
* wrapper are the exact same object (same instance, not just equivalent)*/
@Override
public boolean equals(Object other) {
return obj == ((ObjectEntry)other).obj;
}
/**
* Returns the contained object's identityHashCode. Note that identityHashCode values
* are not guaranteed to be unique from object to object, but the hash code is guaranteed to
* not change over time for a given instance of an Object.
*/
@Override
public int hashCode() {
return System.identityHashCode(obj);
}
}
}
9 回答
System.identityHashCode(yourObject)会将yourObject的'original'哈希码作为整数给出 . 唯一性不是一个实现细节,你不应该依赖它 .
编辑:答案修改后汤姆的评论下面重新 . 内存地址和移动对象 .
Object的javadoc指定了
如果一个类重写了hashCode,则意味着它想要生成一个特定的id,这将(人们可以希望)具有正确的行为 .
您可以使用System.identityHashCode获取任何类的ID .
也许这个快速,肮脏的解决方案可行吗
这也给出了初始化类的实例数 .
hashCode()
方法不用于为对象提供唯一标识符 . 它更确切地将对象的状态(即成员字段的值)消化为单个整数 . 该值主要用于某些基于散列的数据结构(如 Map 和集合),以有效地存储和检索对象 .如果您需要对象的标识符,我建议您添加自己的方法而不是覆盖
hashCode
. 为此,您可以创建如下所示的基本接口(或抽象类) .用法示例:
对于id生成,您可以检查my blog post,我试图解释一些生成唯一ID的方法 .
如果它是您可以修改的类,则可以声明类变量
static java.util.concurrent.atomic.AtomicInteger nextInstanceId
. (你必须以明显的方式给它一个初始值 . )然后声明一个实例变量int instanceId = nextInstanceId.getAndIncrement()
.我提出了这个解决方案,在我的情况下,我在多个线程上创建了对象,并且可以序列化:
只是为了从不同的角度增加其他答案 .
如果你想从'above'重用hashcode,并使用你的类'immutatable state派生新的hashcode,那么对super的调用将起作用 . 虽然这可能/可能不会一直级联到Object(即某些祖先可能不会调用super),但它将允许您通过重用来派生哈希码 .
hashCode()和identityHashCode()之间有区别 . 对于两个不等(用==测试)对象o1,o2 hashCode()可能是相同的 . 请参阅下面的示例,这是如何实现的 .
我有同样的问题,到目前为止对任何答案都不满意,因为他们都没有保证唯一的ID .
我也想打印用于调试的对象ID . 我知道必须有一些方法可以做到这一点,因为在Eclipse调试器中,它为每个对象指定唯一的ID .
我提出了一个解决方案,基于以下事实:对象的“==”运算符只有在两个对象实际上是同一个实例时才返回true .
我相信这应该确保程序生命周期内的唯一ID . 但请注意,您可能不希望在 生产环境 应用程序中使用它,因为它维护对您为其生成ID的所有对象的引用 . 这意味着您创建ID的任何对象都不会被垃圾回收 .
由于我将其用于调试目的,我不太关心被释放的内存 .
您可以修改此选项以允许清除对象或删除单个对象(如果需要释放内存) .