source

hashCode()를 덮어쓰는 객체의 고유 ID를 얻으려면 어떻게 해야 합니까?

goodcode 2022. 8. 20. 19:00
반응형

hashCode()를 덮어쓰는 객체의 고유 ID를 얻으려면 어떻게 해야 합니까?

Java 의 클래스가 hashCode() 를 덮어쓰지 않는 경우, 이 클래스의 인스턴스를 인쇄하면, 적절한 고유 번호가 표시됩니다.

개체의 Javadoc은 hashCode()에 대해 다음과 같이 말합니다.

클래스 오브젝트에 의해 정의된hashCode 메서드는 합리적으로 실용적인 만큼 개별 오브젝트에 대해 개별 정수를 반환합니다.

그러나 클래스가 hashCode()를 덮어쓸 경우 고유 번호를 얻으려면 어떻게 해야 합니까?

System.IDHashCode(yourObject)는 yourObject의 원래 해시 코드를 정수로 제공합니다.일의성이 반드시 보장되는 것은 아닙니다.Sun JVM 구현은 이 개체의 원래 메모리 주소와 관련된 값을 제공하지만, 이는 구현 세부 사항이므로 이 주소에 의존해서는 안 됩니다.

편집: 아래 Tom의 코멘트에 따라 수정한 답변입니다.메모리 주소와 이동 객체입니다.

javadoc for Object는 다음과 같이 지정합니다.

이는 일반적으로 객체의 내부 주소를 정수로 변환함으로써 구현되지만 JavaTM 프로그래밍 언어에서는 이 구현 기술이 필요하지 않습니다.

클래스가 hashCode를 덮어쓰는 경우, 이는 특정 ID를 생성해야 함을 의미합니다.이 ID는 올바른 동작을 할 수 있습니다.

System.identity를 사용할 수 있습니다.임의의 클래스의 ID를 취득하기 위한 HashCode.

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;
    }
}

초기화 중인 클래스의 인스턴스 수도 표시됩니다.

// looking for that last hex?
org.joda.DateTime@57110da6

만약 당신이 그것을 들여다보고 있다면hashcodeJava 타입은 다음과 같습니다..toString()오브젝트의 기본 코드는 다음과 같습니다.

Integer.toHexString(hashCode())

수정할 수 있는 클래스인 경우 클래스 변수를 선언할 수 있습니다.static java.util.concurrent.atomic.AtomicInteger nextInstanceId(명확한 방법으로 초기값을 지정해야 합니다.) 다음 변수를 합니다.int instanceId = nextInstanceId.getAndIncrement().

여러 스레드에 개체를 만들고 직렬화할 수 있는 경우에 사용할 수 있는 이 솔루션을 생각해 냈습니다.

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;
    }
}

저도 같은 문제를 안고 있었고, 어떤 답변도 고유 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를 생성하는 개체는 가비지가 수집되지 않습니다.

디버깅을 위해 사용하고 있기 때문에 메모리가 해방되는 것은 그다지 염려되지 않습니다.

메모리 여유 공간이 문제가 되는 경우 개체를 지우거나 개별 개체를 제거할 수 있도록 이 옵션을 수정할 수 있습니다.

다른 각도에서 다른 답을 늘리기 위해서요

위'에서 해시 코드를 재사용하고 클래스의 불변 상태를 사용하여 새로운 해시 코드를 도출하려면 super 호출이 작동합니다.오브젝트까지 캐스케이드 할 수도 있고 아닐 수도 있지만(즉, 일부 상위 항목이 슈퍼를 호출하지 않을 수도 있음), 재사용을 통해 해시 코드를 도출할 수도 있습니다.

@Override
public int hashCode() {
    int ancestorHash = super.hashCode();
    // now derive new hash from ancestorHash plus immutable instance vars (id fields)
}

hashCode()와 ID 사이에는 차이가 있습니다.HashCode()가 반환됩니다.두 개의 동일하지 않은(==와 동일하지 않은) 개체 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");
        }
    }
}

언급URL : https://stackoverflow.com/questions/909843/how-to-get-the-unique-id-of-an-object-which-overrides-hashcode

반응형