Springen naar inhoud

Java hashtable probleem


  • Log in om te kunnen reageren

#1

Math-E-Mad-X

    Math-E-Mad-X


  • >1k berichten
  • 2382 berichten
  • Ervaren gebruiker

Geplaatst op 10 december 2010 - 13:47

Wie kan mij deze bug uitleggen? Ik heb een class genaamd Order, een arraylist van Order-objecten en een Hashtable die aan iedere Order een vector van Order-objecten toekent.

ArrayList<Order> orders;
Order ord1;
HashTable<Order, Vector<Order>> supports;

...
...

for(Order ord2 : orders){
	if(ord1.equals(ord2)){
		if(supports.get(ord1) == null){
		   System.out.println("something went wrong");
		}
		if(supports.get(ord2) == null){
		   System.out.println("something went wrong2");
		}					
	}
}

Deze code print alleen "something went wrong". Dit is vreemd, aangezien ord1.equals(ord2) true geeft, zou je verwachten dat het niet uitmaakt of je supports.get(ord1) of supports.get(ord2) doet, dus zouden beide teksten geprint moeten worden. :S
while(true){ Thread.sleep(60*1000/180); bang_bassdrum(); }

Dit forum kan gratis blijven vanwege banners als deze. Door te registeren zal de onderstaande banner overigens verdwijnen.

#2

Math-E-Mad-X

    Math-E-Mad-X


  • >1k berichten
  • 2382 berichten
  • Ervaren gebruiker

Geplaatst op 10 december 2010 - 14:27

ohja, vergeten erbij te vermelden: de class Order implementeert geen nieuwe equals() methode, dus het gaat hier gewoon om de equals() methode die is overgeŽrfd van Object.
while(true){ Thread.sleep(60*1000/180); bang_bassdrum(); }

#3

Bart

    Bart


  • >5k berichten
  • 7224 berichten
  • VIP

Geplaatst op 10 december 2010 - 16:57

equals() vergelijkt references en geen values. Als obj1 en obj2 beide een null reference hebben, dan zal obj1.equals(obj2) true terug geven

De standaard equals() methode in Java is gelijk aan "=="
If I have seen further it is by standing on the shoulders of giants.-- Isaac Newton

#4

317070

    317070


  • >5k berichten
  • 5567 berichten
  • Moderator

Geplaatst op 10 december 2010 - 17:25

ohja, vergeten erbij te vermelden: de class Order implementeert geen nieuwe equals() methode, dus het gaat hier gewoon om de equals() methode die is overgeŽrfd van Object.

a)Daar heb je je probleem. De equals-methode van Object vergelijkt pointers, zoals Bart al aangaf, en mag je dus NOOIT gebruiken (idem met de hashcode). Dus object.clone().equals(object)==false
b)als je hashen wil gebruiken, MOET je dus zelf een methode equals en een methode hashcode implementeren.
c) hashtable mag je niet gebruiken, hij wordt deprecated. HashMap is het juiste alternatief.
What it all comes down to, is that I haven't got it all figured out just yet
And I've got one hand in my pocket and the other one is giving the peace sign
-Alanis Morisette-

#5

Math-E-Mad-X

    Math-E-Mad-X


  • >1k berichten
  • 2382 berichten
  • Ervaren gebruiker

Geplaatst op 10 december 2010 - 17:46

equals() vergelijkt references en geen values. Als obj1 en obj2 beide een null reference hebben, dan zal obj1.equals(obj2) true terug geven

De standaard equals() methode in Java is gelijk aan "=="

ja, dat snap ik, maar allebei de variabelen zijn niet null, dat heb ik gechecked.

Veranderd door Math-E-Mad-X, 10 december 2010 - 17:52

while(true){ Thread.sleep(60*1000/180); bang_bassdrum(); }

#6

Math-E-Mad-X

    Math-E-Mad-X


  • >1k berichten
  • 2382 berichten
  • Ervaren gebruiker

Geplaatst op 10 december 2010 - 17:56

a)Daar heb je je probleem. De equals-methode van Object vergelijkt pointers, zoals Bart al aangaf, en mag je dus NOOIT gebruiken (idem met de hashcode). Dus object.clone().equals(object)==false
b)als je hashen wil gebruiken, MOET je dus zelf een methode equals en een methode hashcode implementeren.
c) hashtable mag je niet gebruiken, hij wordt deprecated. HashMap is het juiste alternatief.

Het is Łberhaupt nooit de bedoeling geweest om de equals() methode te gebruiken. Het probleem was dat supports.get(ord1) null geeft, terwijl supports.get(ord2) dat niet doet, terwijl ik dacht dat ord1 en ord2 toch echt naar hetzelfde object refereerden. De equals() methode heb ik hier dus alleen gebruikt om te checken of mijn hypothese klopte. En inderdaad blijken beide pointers naar hetzelfde object te verwijzen. Dus begrijp ik het probleem nog steeds niet. ;)

c) hashtable mag je niet gebruiken, hij wordt deprecated. HashMap is het juiste alternatief.

Bedankt voor de tip! ;)
while(true){ Thread.sleep(60*1000/180); bang_bassdrum(); }

#7

Math-E-Mad-X

    Math-E-Mad-X


  • >1k berichten
  • 2382 berichten
  • Ervaren gebruiker

Geplaatst op 12 december 2010 - 11:58

Hangt hier werkelijk niemand rond die genoeg van java weet om mij dit probleem uit te leggen??? ;)
while(true){ Thread.sleep(60*1000/180); bang_bassdrum(); }

#8

Cycloon

    Cycloon


  • >1k berichten
  • 4810 berichten
  • VIP

Geplaatst op 12 december 2010 - 14:59

Edit: Wat ik hier te zeggen had klopte niet ;)

Veranderd door Cycloon, 12 december 2010 - 15:10


#9

Cycloon

    Cycloon


  • >1k berichten
  • 4810 berichten
  • VIP

Geplaatst op 12 december 2010 - 15:32

Heb je ord1 en ord2 al eens gewoon afgedrukt en gekeken of ze dezelfde referentie hebben?

#10

317070

    317070


  • >5k berichten
  • 5567 berichten
  • Moderator

Geplaatst op 12 december 2010 - 15:47

Hangt hier werkelijk niemand rond die genoeg van java weet om mij dit probleem uit te leggen??? ;)

Ik weet veel van Java, ik heb al op mijn eentje een full-blown media-managment programma gemaakt (lees: mp3 afspelen, binnen Java videos afspelen met de hulp van VLC-dll files die ik binnenhaalde via JNA, youtube-crawler en videos downloaden van youtube, dynamisch klassen binnenhalen die niet met mijn programma gecompiled zijn om als plugin te gebruiken, ...) Zie: http://sourceforge.n.../lyricscatcher/

Maar, als je je niet aan de regels van het coderen houdt (lees: niet zelf de equals en hashcode implementeert) dan kan uiteraard vanalles misgaan. De regel is:

# If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
# It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hashtables.

In jouw implementatie zijn de 2 bovenstaande regels dus niet vervuld. Als je de functies equals() en hashcode() niet geÔmplementeerd hebt, is het nogal vanzelfsprekend dat het niet werkt.

Waarom het precies niet werkt is een veel moeilijkere vraag. Daarvoor moet je iets af kennen van de Java compiler en de JVM, en daar weet ik niets vanaf. Maar dat is dan ook een vrij zinloze vraag...

Edit: ik heb precies een stapje overgeslagen. De hashcode is afhankelijk van de JVM omwille van:

The default hashCode() method uses the 32-bit internal JVM address of the Object as its hashCode. However, if the Object is moved in memory during garbage collection, the hashCode stays constant. This default hashCode is not very useful, since to look up an Object in a HashMap, you need the exact same key Object by which the key/value pair was originally filed. Normally, when you go to look up, you don’t have the original key Object itself, just some data for a key. So, unless your key is a String, nearly always you will need to implement a hashCode and equals method on your key class. Object.hashCode in a native method.

http://mindprod.com/...s/hashcode.html
What it all comes down to, is that I haven't got it all figured out just yet
And I've got one hand in my pocket and the other one is giving the peace sign
-Alanis Morisette-

#11

Math-E-Mad-X

    Math-E-Mad-X


  • >1k berichten
  • 2382 berichten
  • Ervaren gebruiker

Geplaatst op 12 december 2010 - 16:16

Heb je ord1 en ord2 al eens gewoon afgedrukt en gekeken of ze dezelfde referentie hebben?

hoe doe je dit in java? Bedoel je het geheugenadres waar ze naar verwijzen afdrukken?
while(true){ Thread.sleep(60*1000/180); bang_bassdrum(); }

#12

Math-E-Mad-X

    Math-E-Mad-X


  • >1k berichten
  • 2382 berichten
  • Ervaren gebruiker

Geplaatst op 12 december 2010 - 16:30

@317070: Dus om HashTable / HashMap te gebruiken moet je eerst helemaal zelf een eigen HashCode gaan lopen definiŽren? Niet echt praktisch....

Is er dan geen andere datastructuur die ik kan gebruiken om simpelweg objecten van klasse A naar objecten van klasse B te mappen? Ik kan wel wat manieren verzinnen om zoiets zelf te implementeren, maar ik had toch wel gedacht dat er een ready-to-use datastructuur was die dat voor je doet.
while(true){ Thread.sleep(60*1000/180); bang_bassdrum(); }

#13

317070

    317070


  • >5k berichten
  • 5567 berichten
  • Moderator

Geplaatst op 12 december 2010 - 16:37

@317070: Dus om HashTable / HashMap te gebruiken moet je eerst helemaal zelf een eigen HashCode gaan lopen definiŽren? Niet echt praktisch....

Is er dan geen andere datastructuur die ik kan gebruiken om simpelweg objecten van klasse A naar objecten van klasse B te mappen? Ik kan wel wat manieren verzinnen om zoiets zelf te implementeren, maar ik had toch wel gedacht dat er een ready-to-use datastructuur was die dat voor je doet.

Meuh, dat is toch geen werk om dat zelf te implementeren.

Uit mijn duim
public int hashCode()
{
   int hash = 0;
   hash = 31 * hash + field1.hashcode();
   hash = 31 * hash + field2.hashcode();
   hash = 31 * hash + field3.hashcode();
   hash = 31 * hash + field4.hashcode();
   return hash;
}
gewoon op al je velden die je wil hebben in je code invullen. Je hashcode moet ook helemaal niet goed werken om te werken...

Nu als ik het goed begrijp gebruik je toch identieke objecten om dan terug in je hashtable op te zoeken. Is het dan niet logischer om gewoon een veld met object B binnen je object A op te slaan?
What it all comes down to, is that I haven't got it all figured out just yet
And I've got one hand in my pocket and the other one is giving the peace sign
-Alanis Morisette-

#14

Math-E-Mad-X

    Math-E-Mad-X


  • >1k berichten
  • 2382 berichten
  • Ervaren gebruiker

Geplaatst op 12 december 2010 - 16:42

In jouw implementatie zijn de 2 bovenstaande regels dus niet vervuld.

Sorry, dit snap ik niet.

punt 1) De default HashCode gebruikt toch juist het adres? Dus als twee objecten hetzelfde adres hebben, hebben ze logischerwijs ook dezelfde HashCode.

punt 2) Dit punt lijkt me sowieso niet van toepassing op mijn probleem, omdat het bij mij juist om twee objecten gaat die wel hetzelfde adres hebben.

Blijkbaar begrijp ik je helemaal verkeerd, want voor zover ik zie zijn deze twee punten dus wel vervuld. ;)

Nu als ik het goed begrijp gebruik je toch identieke objecten om dan terug in je hashtable op te zoeken. Is het dan niet logischer om gewoon een veld met object B binnen je object A op te slaan?

Ja, maar het probleem is dat ik deze klassen niet zelf geschreven heb, ze komen uit een framework.
while(true){ Thread.sleep(60*1000/180); bang_bassdrum(); }

#15

317070

    317070


  • >5k berichten
  • 5567 berichten
  • Moderator

Geplaatst op 12 december 2010 - 16:49

ArrayList<Order> orders;
Order ord1;
HashTable<Order, Vector<Order>> supports;

...
...

for(Order ord2 : orders){
	if(ord1 == ord2){
		if(supports.get(ord1) == null){
		   System.out.println("something went wrong");
		}
		if(supports.get(ord2) == null){
		   System.out.println("something went wrong2");
		}					
	}
}
Wat gebeurt er met deze code? Misschien is de equals() methode in je framework overridden, zonder dat je het weet, maar de hashcode() niet.
What it all comes down to, is that I haven't got it all figured out just yet
And I've got one hand in my pocket and the other one is giving the peace sign
-Alanis Morisette-





0 gebruiker(s) lezen dit onderwerp

0 leden, 0 bezoekers, 0 anonieme gebruikers

Ook adverteren op onze website? Lees hier meer!

Gesponsorde vacatures

Vacatures