Soru HashCode () işlevini geçersiz kılan bir nesnenin benzersiz kimliği nasıl alınır?


Java'daki bir sınıf geçersiz kılmazsa hash kodu(), Bu sınıfın bir örneğini yazdırmak hoş bir benzersiz sayı verir.

Nesnenin Javadocu şöyle diyor: hash kodu():

Oldukça pratik olduğu kadarıyla, sınıf nesnesi tarafından tanımlanan hashCode yöntemi, farklı nesneler için farklı tamsayılar döndürür.

Fakat sınıf geçersiz kıldığında hash kodu(), nasıl alabilirim Bu benzersiz bir numara mı?


193
2018-05-26 09:42


Menşei


Çoğunlukla 'hata ayıklama' nedenleri;) Söylemek mümkün: Ah, aynı nesne! - ivan_ivanovich_ivanoff
Bu amaçla System.identityHashcode () bazı kullanım olasılıklarıdır. Bununla birlikte, kod işlevselliğini uygulamak için buna güvenmem. Nesneleri benzersiz bir şekilde tanımlamak isterseniz, AspectJ ve kod örgüsünü, oluşturulan her nesne için benzersiz bir kimlikte kullanabilirsiniz. Daha fazla çalışma olsa da - Brian Agnew
Yalnızca hashCode'un benzersiz olması garanti edilmediğini unutmayın. Uygulamanın bellek adresi varsayılan hashCode olarak kullanılsa bile. Neden eşsiz değil? Çünkü nesneler çöp toplar ve hafıza yeniden kullanılır. - Igor Krivokon
Eğer karar vermek isterseniz, iki nesne aynı ise hashCode () yerine == kullanın. Sonuncusu, orijinal uygulamada bile benzersiz değildir. - Mnementh
Cevapların hiçbiri gerçek soruya cevap vermez, çünkü burada rastlantısal olan hashCode () 'ı tartışmaya karışmışlar. Eclipse'deki referans değişkenlerine baktığımda, bana benzersiz bir immutable "id = xxx" gösteriyor. Kendi belirleyicimizi kullanmak zorunda kalmadan programatik olarak bu değere nasıl ulaşabiliriz? Farklı nesne örneklerini tanımlamak için hata ayıklama amacıyla (günlüğe kaydetme) bu değere erişmek istiyorum. Ellerini o değere nasıl çıkaracağını bilen var mı? - Chris Westin


Cevaplar:


System.identityHashCode (yourObject) YourObject öğesinin 'orijinal' karma kodunu bir tam sayı olarak verecektir. Teklik mutlaka garanti edilmez. Sun JVM uygulaması size bu nesnenin orijinal bellek adresi ile ilgili bir değer verecektir, ancak bu bir uygulama detayıdır ve buna güvenmemelisiniz.

DÜZENLEME: Tom'un yorumunu takip eden yanıt, aşağıdaki re. hafıza adresleri ve hareketli nesneler.


293
2018-05-26 09:46



Tahmin edeyim: Eşsiz değil, aynı JVM'de 2'den fazla 32 nesne var mı? ;) Beni tarif ettiği benzersizliğin olmadığı bir yere yönlendirebilir misin? Thanx! - ivan_ivanovich_ivanoff
Orada kaç tane nesne var, ne kadar hafıza var. Benzersiz bir sayı üretmek için hashCode () veya identityHashCode () gerekmemektedir. - Alan Moore
Brian: Bu gerçek hafıza konumu değil, ilk hesaplandığında adresin yeniden yazılmış bir versiyonunu elde edersiniz. Modern bir VM nesnesi hafızada hareket edecektir. - Tom Hawtin - tackline
Teklik değil garantili Pratik bir JVM uygulaması için. Garantili teklik, ya GC tarafından herhangi bir yer değiştirme / sıkıştırma gerekliliğini ya da canlı nesnelerin hashcode değerlerini yönetmek için büyük ve pahalı bir veri yapısı gerektirir. - Stephen C
System.identityHashCode, HotSpot'ta benzersiz DEĞİL, zor yoldan öğrendim .. - R.Moeller


Nesne için javadoc şunu belirtir

Bu genellikle, nesnenin dahili adresini bir tam sayıya dönüştürerek uygulanır, ancak bu uygulama tekniği, JavaTM programlama dili tarafından gerekli değildir.

Bir sınıf hashCode'u geçersiz kılarsa, bu, belirli bir kimliği oluşturmak istediği anlamına gelir;

Kullanabilirsiniz System.identityHashCode herhangi bir sınıf için bu kimliği almak için.


27
2018-05-26 09:47





Belki bu hızlı, kirli çözüm işe yarayacak?

public class A {
    static int UNIQUE_ID = 0;
    int uid = ++UNIQUE_ID;

    public int hashCode() {
        return uid;
    }
}

Bu ayrıca başlatılan bir sınıfın örnek sayısını verir.


7
2017-11-21 22:48



Bu, sınıfın kaynak koduna erişiminiz olduğunu varsayar - pablisco
Kaynak koduna erişemiyorsanız, oradan uzatın ve genişletilmiş sınıfı kullanın. Basit, hızlı, kolay ve kirli çözüm ama işe yarıyor. - John Pang
her zaman işe yaramıyor. Ders final olabilir. bence System.identityHashCode daha iyi bir çözüm - pablisco
Diş güvenli değil. - user2357
Vida dişi güvenliği için AtomicLong de olduğu gibi bu cevap. - Evgeni Sergeev


hashCode() yöntem, bir nesne için benzersiz bir tanımlayıcı sağlamak için değildir. Nesnenin durumunu (yani, üye alanların değerleri) tek bir tam sayıya doğru sindirir. Bu değer çoğunlukla, nesneleri ve depoları etkili bir şekilde saklamak için haritalar ve kümeler gibi bazı karma tabanlı veri yapıları tarafından kullanılır.

Nesneleriniz için bir tanımlayıcıya ihtiyacınız varsa, geçersiz kılmak yerine kendi yönteminizi eklemenizi öneririz. hashCode. Bu amaçla, aşağıdaki gibi bir temel arayüz (veya soyut bir sınıf) oluşturabilirsiniz.

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

Örnek kullanım:

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

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

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

Kimlik üretimi için kontrol edebilirsiniz blog gönderim benzersiz kimlikler oluşturmanın bazı yollarını açıklamaya çalıştım.


7
2018-01-02 11:40





Değiştirebileceğiniz bir sınıfsa, bir sınıf değişkeni bildirebilirsiniz. static java.util.concurrent.atomic.AtomicInteger nextInstanceId. (Açık bir şekilde bir başlangıç ​​değeri vermelisiniz.) Sonra bir örnek değişken bildirin int instanceId = nextInstanceId.getAndIncrement().


3
2018-01-08 14:32





Birden çok iş parçacığı üzerinde oluşturduğum nesnelerin olduğu ve serileştirilebilen bir durumda çalıştığım bu çözümle geldim:

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

1
2017-12-09 21:22





Diğer cevapları sadece farklı açılardan arttırmak için.

Eğer hash kodu (kodlarını) 'üstünden' tekrar kullanmak ve sınıfınızı 'değişmez halini kullanarak yenilerini türetmek istiyorsanız, o zaman süper arama yapılacaktır. Bu, Nesne'ye kadar tümüyle ilerletilemez / olmayabilir (yani, bazı atalar süper arama yapamaz), yeniden kodları kullanarak yeniden kod elde etmenizi sağlar.

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

0
2017-07-24 03:44





HashCode () ve identityHashCode () döndürmeleri arasında bir fark var. İki eşitsiz (== ile test edilmiş) nesneler o1 için, o2 hashCode () aynı olabilir. Bunun nasıl doğru olduğunu aşağıdaki örneğe bakın.

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

0
2017-11-14 06:40





Aynı sorunu yaşadım ve hiçbir cevaptan memnun olmadım, çünkü hiçbiri benzersiz kimlikler garanti etmiyordu.

Ben de hata ayıklama için nesne kimlikleri yazdırmak istedim. Bunu yapmanın bir yolu olması gerektiğini biliyordum çünkü Eclipse hata ayıklayıcıda, her nesne için benzersiz kimlikler belirliyor.

Nesneler için "==" işlecinin, yalnızca iki nesne aslında aynı örnek ise yalnızca doğru döndüğü gerçeğine dayalı bir çözüm buldum.

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

Bunun, programın ömrü boyunca benzersiz kimlikler sağlaması gerektiğine inanıyorum. Bununla birlikte, bunu bir üretim uygulamasında kullanmak istemediğinizi unutmayın, çünkü kimlikleri oluşturduğunuz tüm nesnelerin referanslarını tutar. Bu, kimliğinizi oluşturduğunuz nesnelerin asla çöp toplamayacağı anlamına gelir.

Bunu hata ayıklama amaçları için kullandığım için, boşaltılan bellekle fazla ilgilenmiyorum.

Belleği boşaltırsa, nesnelerin temizlenmesi veya tek tek nesneleri kaldırma izni vermek için bunu değiştirebilirsiniz.


0
2017-09-13 21:28