Java의 클래스가 hashCode ()를 재정의하지 않으면 이 클래스의 인스턴스를 인쇄하면 고유 한 숫자가 나타납니다.
Object의 Javadoc은 hashCode () 에 대해 말합니다 .
합리적으로 실용적이기는하지만 Object 클래스에 의해 정의 된 hashCode 메소드는 개별 오브젝트에 대해 고유 정수를 리턴합니다.
그러나 클래스가 hashCode ()를 재정의 하면 고유 번호를 어떻게 얻을 수 있습니까?
Java의 클래스가 hashCode ()를 재정의하지 않으면 이 클래스의 인스턴스를 인쇄하면 고유 한 숫자가 나타납니다.
Object의 Javadoc은 hashCode () 에 대해 말합니다 .
합리적으로 실용적이기는하지만 Object 클래스에 의해 정의 된 hashCode 메소드는 개별 오브젝트에 대해 고유 정수를 리턴합니다.
그러나 클래스가 hashCode ()를 재정의 하면 고유 번호를 어떻게 얻을 수 있습니까?
답변:
System.identityHashCode (yourObject) 는 yourObject 의 '원래'해시 코드를 정수로 제공합니다. 독창성이 반드시 보장되는 것은 아닙니다. Sun JVM 구현은이 객체의 원래 메모리 주소와 관련된 값을 제공하지만 이는 구현 세부 사항이므로 의존해서는 안됩니다.
편집 : re 아래 Tom의 의견에 따라 수정 된 답변. 메모리 주소와 움직이는 물체.
System.identityHashCode()
입니까?
Object 용 javadoc은 다음을 지정합니다.
이는 일반적으로 오브젝트의 내부 주소를 정수로 변환하여 구현되지만이 구현 기술은 JavaTM 프로그래밍 언어에 필요하지 않습니다.
클래스가 hashCode를 재정의하면 특정 ID를 생성하고 싶다는 것을 의미합니다.
System.identityHashCode 를 사용 하여 모든 클래스의 해당 ID를 얻을 수 있습니다 .
hashCode()
이 방법은 객체에 고유 식별자를 제공하기위한 것이 아닙니다. 오히려 객체의 상태 (즉, 멤버 필드의 값)를 단일 정수로 요약합니다. 이 값은 주로 객체를 효과적으로 저장하고 검색하기 위해 맵 및 세트와 같은 일부 해시 기반 데이터 구조에서 사용됩니다.
객체의 식별자가 필요한 경우 재정의 대신 고유 한 방법을 추가하는 것이 좋습니다 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 class A {
static int UNIQUE_ID = 0;
int uid = ++UNIQUE_ID;
public int hashCode() {
return uid;
}
}
또한 초기화되는 클래스의 인스턴스 수를 제공합니다.
System.identityHashCode
더 나은 솔루션 이라고 생각 합니다
AtomicLong
을 위해이 답변 과 같이 사용할 수 있습니다 .
여러 스레드에서 객체를 만들고 직렬화 할 수있는 경우에 작동하는이 솔루션을 생각해 냈습니다.
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;
}
}
다른 대답을 다른 각도에서 보완하기 위해.
'위'에서 해시 코드를 재사용하고 클래스의 불변 상태를 사용하여 새 코드를 파생 시키려면 super에 대한 호출이 작동합니다. 이것은 Object까지 완전히 계단식으로 배열되지 않을 수도 있지만 (즉, 일부 조상은 super를 호출하지 않을 수도 있음) 재사용을 통해 해시 코드를 파생시킬 수 있습니다.
@Override
public int hashCode() {
int ancestorHash = super.hashCode();
// now derive new hash from ancestorHash plus immutable instance vars (id fields)
}
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");
}
}
}
나는 동일한 문제가 있었고 지금까지 아무도 고유 ID를 보장하지 않았기 때문에 어떤 대답에도 만족하지 못했습니다.
디버깅 목적으로 객체 ID를 인쇄하고 싶었습니다. Eclipse 디버거에서 각 객체의 고유 ID를 지정하기 때문에 어떤 방법이 있어야한다는 것을 알고있었습니다.
두 객체가 실제로 동일한 인스턴스 인 경우 객체에 대한 "=="연산자 만 true를 반환한다는 사실에 기반한 솔루션을 생각해 냈습니다.
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);
}
}
}
이것이 프로그램의 수명 기간 동안 고유 한 ID를 보장해야한다고 생각합니다. 그러나 ID를 생성하는 모든 객체에 대한 참조를 유지하므로 프로덕션 응용 프로그램에서 이것을 사용하지 않을 수도 있습니다. 즉, ID를 생성하는 모든 객체는 가비지 수집되지 않습니다.
디버그 목적으로 이것을 사용하고 있기 때문에 해제되는 메모리에 대해서는별로 신경 쓰지 않습니다.
메모리를 확보해야하는 경우 오브젝트를 지우거나 개별 오브젝트를 제거 할 수 있도록이를 수정할 수 있습니다.