ToString () ve hashCode () geçersiz kılındığında java'da bir nesnenin “nesne başvurusunu” nasıl elde edersiniz?


106

Hata ayıklama amacıyla Java'daki bir nesnenin "nesne başvurusunu" yazdırmak istiyorum. Yani, duruma bağlı olarak nesnenin aynı (veya farklı) olduğundan emin olmak.

Sorun, söz konusu sınıfın, genellikle bana kimliği verecek olan hem toString () hem de hashCode () 'u geçersiz kılan başka bir sınıftan miras almasıdır.

Örnek durum: Çok iş parçacıklı bir uygulamanın çalıştırılması, burada (geliştirme sırasında) tüm iş parçacıklarının aynı kaynak nesnesi örneğini kullanıp kullanmadığını kontrol etmek istiyorum.


1
yapıp yapamayacağınıza bağlı olarak ... == gidilecek yol ... ama söz konusu kodun nasıl yapılandırıldığı hakkında hiçbir fikrim yok. Yine hashCode, yaptığınız şey için büyük olasılıkla iyidir, ancak kitaplığın nasıl uygulandığına bağlı olarak bozulabilir.
TofuBeer

Gerçekten güzel bir soru.
Zhang Xiang

Yanıtlar:


108

Onunla tam olarak ne yapmayı planlıyorsunuz (yapmak istediğiniz şey, aramanız gereken şeyle bir fark yaratır).

hashCodeJavaDocs'ta tanımlandığı gibi, diyor ki:

Makul derecede pratik olduğu kadar, Object sınıfı tarafından tanımlanan hashCode yöntemi, farklı nesneler için farklı tamsayılar döndürür. (Bu genellikle nesnenin dahili adresini bir tam sayıya dönüştürerek gerçekleştirilir, ancak bu uygulama tekniği Java ™ programlama dili tarafından gerekli değildir.)

Öyleyse hashCode(), bellekte benzersiz bir nesne olup olmadığını öğrenmek için kullanıyorsanız , bunu yapmanın iyi bir yolu değildir.

System.identityHashCode aşağıdakileri yapar:

Verilen nesnenin sınıfının hashCode () öğesini geçersiz kılıp kılmamasına bakılmaksızın, varsayılan yöntem hashCode () tarafından döndürülenle aynı karma kodu döndürür. Boş referans için hash kodu sıfırdır.

Hangi, yaptığınız şey için, istediğiniz gibi geliyor ... ama yapmak istediğiniz şey, kütüphanenin nasıl uygulandığına bağlı olarak güvenli olmayabilir.


6
Koddaki değere göre hareket etmiyorum. Pr olarak. Soru düzenlemem, onu yalnızca belirli bir durumda hata ayıklama amacıyla kullanıyorum. Bu yüzden cevabımın makul olduğunu düşünüyorum, ancak anlayışlı bir cevap için size +1 veriyorum.
Nicolai

1
Muhtemelen her zaman istediğiniz şeyi yapacak - ancak bazı VM'lerde bozulabilir.
TofuBeer

Herhangi bir makul VM'de kırılacaktır (yani, kimlikHashCode mutlaka benzersiz olmayacaktır). IdentityHashCode bir ID değil
Tom Hawtin - tackline

Bahsedildiği gibi, adrese dayalı karma kodun hiçbir garantisi yoktur. WAS'ın içindeki IBM VM'de aynı kimliğe sahip birden çok nesne gördüm.
Robin

"Bu genellikle nesnenin dahili adresini bir tamsayıya" bir garanti olarak değil, Sun'ın varsayılan uygulamasını dönüştürerek gerçekleştirilir. S = "Merhaba" ve t = "Merhaba" gibi şeyler muhtemelen s ve t'nin gerçekten aynı nesne oldukları gibi aynı IdentityHashCode'a sahip olmasıyla sonuçlanır.
TofuBeer

50

Ben böyle çözdüm:

Integer.toHexString(System.identityHashCode(object));

5
Bu aslında doğru değildir, çünkü birden çok nesne aynı kimlik kodunu döndürebilir.
Robin

2
Aynı kimlik karmasına sahip iki nesnenin (referansların) aynı nesne olduğu doğru değil mi? OP'nin istediği bu
basszero

3
Hayır, bu doğru değil. Muhtemeldir, ancak spesifikasyon algoritmayı tanımlamadığından garanti edilmez.
Robin

8

Double equals ==, nesnelerin hashCode veya equals uygulamasına bakılmaksızın her zaman nesne kimliğine göre kontrol eder. Elbette - karşılaştırdığınız nesne referanslarının volatile(1.5+ JVM'de) olduğundan emin olun .

Orijinal Object toString sonucuna gerçekten sahip olmanız gerekiyorsa (örnek kullanım durumunuz için en iyi çözüm olmasa da), Commons Lang kitaplığının istediğinizi yapacak bir ObjectUtils.identityToString (Object) yöntemi vardır . JavaDoc'tan:

public static java.lang.String identityToString(java.lang.Object object)

Bir sınıf toString'in kendisini geçersiz kılmadıysa, Object tarafından üretilecek toString'i alır. null, null döndürür.

 ObjectUtils.identityToString(null)         = null
 ObjectUtils.identityToString("")           = "java.lang.String@1e23"
 ObjectUtils.identityToString(Boolean.TRUE) = "java.lang.Boolean@7fa"

1
Java 7 kullanıyorsanız, java.util.Objects
noahlz

5

Varsayılan hashCode () adresi döndürmeyebileceğinden ve bundan bahsedildiği için, aynı hashCode'a sahip birden fazla nesnenin mümkün olabileceğinden, istediğinizi güvenli bir şekilde yapamazsınız. İstediğinizi başarmanın tek yolu, söz konusu nesneler için hashCode () yöntemini gerçekten geçersiz kılmak ve hepsinin benzersiz değerler sağladığını garanti etmektir. Sizin durumunuzda bunun mümkün olup olmadığı başka bir sorudur.

Kayıt için, WAS sunucusunda çalışan bir IBM VM'de aynı varsayılan hashcode'a sahip birden çok nesne deneyimledim. Uzak bir önbelleğe yerleştirilen nesnelerin bu nedenle üzerine yazılacağı bir kusurumuz vardı. Varsayılan hashcode'un nesnelerin bellek adresi olduğunu varsaydığım için, bu noktada benim için bir göz açıcı oldu.


2

Tüm örneklerinize benzersiz bir kimlik ekleyin, yani

public interface Idable {
  int id();
}

public class IdGenerator {
  private static int id = 0;
  public static synchronized int generate() { return id++; }
}

public abstract class AbstractSomething implements Idable {
  private int id;
  public AbstractSomething () {
    this.id = IdGenerator.generate();
  }
  public int id() { return id; }
}

AbstractSomething'den genişletin ve bu özelliği sorgulayın. Tek bir sanal makinede güvende olacak (statiği aşmak için sınıf yükleyicilerle oyun oynanmadığı varsayılarak).


Muhtemelen bu senaryoda AtomicInteger kullanacağım - daha yüksek bir verime sahip çünkü senkronizasyon gerekmiyor ve sun.misc.Unsafe
RAnders00

1

string referansını almak için nesne sınıfının tostringindeki kodu kopyalayabiliriz

class Test
{
  public static void main(String args[])
  {
    String a="nikhil";     // it stores in String constant pool
    String s=new String("nikhil");    //with new stores in heap
    System.out.println(Integer.toHexString(System.identityHashCode(a)));
    System.out.println(Integer.toHexString(System.identityHashCode(s)));
  }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.