Permalänk

Jämföra javaobjekt

Hej,
Jag försöker att gemföra två stycken Object i java.

== är fel. Gemför endast referensen, inte vad jag vill. Jag har förstått att det är metoden equals jag vill använda.

Jag försöker implementera en metod för att gemföra två FIFO köer. (Det här är bara ett test, inte min riktiga kod).
Såhär initierar jag mina två köer:

FIFO test = new FIFO(); test.add(new FIFOItem(1)); test.add(new FIFOItem(2)); FIFO test1 = new FIFO(); test1.add(new FIFOItem(1)); test1.add(new FIFOItem(2));

Som ni ser måste dom vara identiska sånär som på minnesadress.

Sedan gemför jag första elementet i köerna:

(test.first().equals(test1.first())

Gemförelsen returnerar false. Hur i hela friden går det till?

Visa signatur

6600K@4,5GHz 1,25V | EVGA 980Ti | Samsung 950 Pro m.2

Permalänk
Hedersmedlem

Du måste nog göra en egen metod för jämförelse.

http://msdn.microsoft.com/en-us/library/aa986701(v=vs.80).asp...

Nu antar jag FIFOItem inte är din egen klass men det beror ju på i vilket avseende de ska vara lika. Det skulle vara ganska begränsande om det var förbestämt av en klass. Nu tvingas man istället bestämma själv hur de ska jämföras.

Jag är inte hundra på det här men det är min gissning.

Permalänk
Medlem

Du har stoppat in olika objekt i dina köer. Om du skulle dumpa ut referensen till dem skulle du se att de länkar till olika minnesallkoeringar. Prova skapa dina "FIFOItem" separat, och sen populera dina köer med dem. Detta förutsatt att equals()-funktionen går igenom kön och jämför innehållet.

http://docs.oracle.com/javase/7/docs/api/java/lang/Object.htm...

Citat:

The equals method for class Object implements the most discriminating possible equivalence relation on objects; that is, for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true).

Du kan ju alltid överlagra equals()-funktionen med en egen implementation i ditt FIFO-objekt som gör det du vill.

Visa signatur

WS: Fractal Design Pop Silent | Seasonic Prime G12 GC 550W | Gigabyte B650 Eagle AX | Ryzen 7 7700 | Corsair 64GB DDR5 | Asus Xonar DX | Arch Linux (x86_64) | Eizo EV2795
HTPC: Philips 50PUS8804, Kodi samt extern usb-disk
Server: Raspberry Pi 4 | 8GB RAM | HDD 750GB | Arch Linux (armv7h)

Permalänk
Skrivet av Shimonu:

Du måste nog göra en egen metod för jämförelse.

http://msdn.microsoft.com/en-us/library/aa986701(v=vs.80).asp...

Nu antar jag FIFOItem inte är din egen klass men det beror ju på i vilket avseende de ska vara lika. Det skulle vara ganska begränsande om det var förbestämt av en klass. Nu tvingas man istället bestämma själv hur de ska jämföras.

Jag är inte hundra på det här men det är min gissning.

FIFOItem är min egen klass.

Skrivet av '[vEX:

;13238192']Du har stoppat in olika objekt i dina köer. Om du skulle dumpa ut referensen till dem skulle du se att de länkar till olika minnesallkoeringar. Prova skapa dina "FIFOItem" separat, och sen populera dina köer med dem. Detta förutsatt att equals()-funktionen går igenom kön och jämför innehållet.

http://docs.oracle.com/javase/7/docs/api/java/lang/Object.htm...

Du kan ju alltid överlagra equals()-funktionen med en egen implementation i ditt FIFO-objekt som gör det du vill.

Jag gemför inte minnesadressen. Det är endast innehållet jag vill gemföra. För primitiva typer är det jätteenkelt.
Här är min equals: (Det här är en skoluppgift, därav tar den en Object och inte en FIFO).

public boolean equals(Object f) { System.out.println(f); System.out.println(this); if (f instanceof FIFO) { if (((FIFO) f).size() != this.size()) { return false; } else if (this.isEmpty() && ((FIFO) f).isEmpty()) { //If both are empty, they are equal resetFromTemp((FIFO) f); return true; } else if (((FIFO) f).first().equals(this.first())) { //If first is equal see if next is equal tempFIFO(); //set up temporary FIFO queues tempFIFO.add(((FIFO) f).first()); //move first object to temporary queue ((FIFO) f).removeFirst(); //Go to next item in queue thisTempFIFO.add(this.first()); this.removeFirst(); return equals(f); //See if next is equal } else if (((FIFO) f).first() != this.first()) { resetFromTemp((FIFO) f); return false; //See if next is equal } } return false; }

Visa signatur

6600K@4,5GHz 1,25V | EVGA 980Ti | Samsung 950 Pro m.2

Permalänk
Medlem

"Det är en skoluppgift så därför tar den ett Object istället för en FIFO." Vad menar du med det?

Om jag förstår dig rätt är FIFO en stack du implementerat själv, och du vill kunna jämföra två FIFO:ar med varandra. Det du gör i din testsats i första posten är att jämföra två FIFOItem, har du ingen equals implementerad för dem kommer de returnera false så länge objekt-referenserna inte stämmer överens.

Med andra ord behöver du implementera equals på FIFOItem OCH på FIFO.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Skrivet av Teknocide:

"Det är en skoluppgift så därför tar den ett Object istället för en FIFO." Vad menar du med det?

Jag menar att eftersom att den gemför två FIFO så borde den ta en FIFO som argument istället för ett Object. Då behöver man inte kolla om den är en instans av FIFO. Dessutom slipper man en del typecasting.

Skrivet av Teknocide:

Om jag förstår dig rätt är FIFO en stack du implementerat själv, och du vill kunna jämföra två FIFO:ar med varandra. Det du gör i din testsats i första posten är att jämföra två FIFOItem, har du ingen equals implementerad för dem kommer de returnera false så länge objekt-referenserna inte stämmer överens.

Med andra ord behöver du implementera equals på FIFOItem OCH på FIFO.

Jag kan implementera en equals på FIFOItem. Det ska inte behövas. FIFO har en metod, first(), som returnerar det Object som ligger först i kön, vilket inte är en FIFOItem.
FIFO:

public Object first() { if (this.fifoItems == null) { throw new NoSuchElementException() ; } else { return fifoItems.getStoredObject(); } }

FIFOItem:

private FIFOItem next = null; private Object storedObject = null; Object getStoredObject() { return storedObject; }

Gemförelsen:

((FIFO) f).first().equals(this.first())

Gemför således inte två FIFOItem.

Det är detta test som inte fungerar. Jag gör fel, men inte på det sett du beskriver. Om jag implementerar equals på FIFOItem har jag bara förflyttat mitt problem ett steg. Jag hoppas att jag utrycker mig tydligare nu.

Visa signatur

6600K@4,5GHz 1,25V | EVGA 980Ti | Samsung 950 Pro m.2

Permalänk
Medlem
Skrivet av tomten_alle:

Jag menar att eftersom att den gemför två FIFO så borde den ta en FIFO som argument istället för ett Object. Då behöver man inte kolla om den är en instans av FIFO. Dessutom slipper man en del typecasting.

Jag kan implementera en equals på FIFOItem. Det ska inte behövas. FIFO har en metod, first(), som returnerar det Object som ligger först i kön, vilket inte är en FIFOItem.
FIFO:

public Object first() { if (this.fifoItems == null) { throw new NoSuchElementException() ; } else { return fifoItems.getStoredObject(); } }

FIFOItem:

private FIFOItem next = null; private Object storedObject = null; Object getStoredObject() { return storedObject; }

Gemförelsen:

((FIFO) f).first().equals(this.first())

Gemför således inte två FIFOItem.

Det är detta test som inte fungerar. Jag gör fel, men inte på det sett du beskriver. Om jag implementerar equals på FIFOItem har jag bara förflyttat mitt problem ett steg. Jag hoppas att jag utrycker mig tydligare nu.

Ok, jag är med.

Jag vet inte om du egentligen behöver en FIFOItem eller FIFO, det känns som att deras anvarsområde ligger omlott, och du använder ju faktiskt aldrig din FIFOItem; du bara stoppar in den och sedan är den "borta". Det enda som någonsin kommer tillbaka är objektet inuti.

När du jobbar mot din tempFIFO i equals-metoden skapar du inte ett FIFOItem-objekt; du stoppar in resultatet av .first() utan ceremoni. Såvida du inte använder en subklass av FIFO när du sätter upp tempkön med tempFIFO har du en bug här. Skulle du använda en subklass som wrappar inkommande objekt i en FIFOItem verkar det lite underligt att du inte gör det varje gång.

Det finns lite andra frågetecken, som varför du dekonstruerar och rekonstruerar hela din kö varje gång du kommer in i equals. Jag antar även att tempFIFO-metoden har ett inbyggd mekanism som förhindrar att den skapar om sig själv för varje rekursion. Att kolla size varje gång du går igenom equals är också överflödigt.

edit: La precis märke till en grej nu.
Du skriver ((FIFO) f).first().equals(this.first()). Hur kan du casta första elementet till en FIFO? Det kan ju vara vad som helst

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Skrivet av Teknocide:

Ok, jag är med.

Jag vet inte om du egentligen behöver en FIFOItem eller FIFO, det känns som att deras anvarsområde ligger omlott, och du använder ju faktiskt aldrig din FIFOItem; du bara stoppar in den och sedan är den "borta". Det enda som någonsin kommer tillbaka är objektet inuti.

När du jobbar mot din tempFIFO i equals-metoden skapar du inte ett FIFOItem-objekt; du stoppar in resultatet av .first() utan ceremoni. Såvida du inte använder en subklass av FIFO när du sätter upp tempkön med tempFIFO har du en bug här. Skulle du använda en subklass som wrappar inkommande objekt i en FIFOItem verkar det lite underligt att du inte gör det varje gång.

Det finns lite andra frågetecken, som varför du dekonstruerar och rekonstruerar hela din kö varje gång du kommer in i equals. Jag antar även att tempFIFO-metoden har ett inbyggd mekanism som förhindrar att den skapar om sig själv för varje rekursion. Att kolla size varje gång du går igenom equals är också överflödigt.

Jag använder dom lite omlott ja. Tanken var först att implementera en vettig variant i FIFOItem, för att sedan göra typ en wrapper för att passa uppgiftsbeskrivningen. Sedan har jag felsökt och strukturerat om till förbannelse, ofta sena kvällar under tidspress. Resulatet, precis som du säger, är inte optimalt. Dessutom försöker jag träna på rekursiva metoder.

Du har rätt att jag inte behöver gemföra storleken varje gång. Det blir mycket uträkningar i onödan. Jag behöver inte ens kolla om dom är tomma. Tack!

Jag måste tyvärr dekonstruera varje varv för att komma vidare. Min FIFOItem har möjlighet att göra på ett annat vis. Jag måste dock hålla mig till en viss tillhandahållen specifikation.

Vad menar du med mekanism som förhindrar att den skapar om sig själv? Allting sker väl per referens eftersom att det inte är primitiva datatyper? Jag tycker att det är lite otydligt när man inte sätter ut egna pekare, men det är väl en vanesak...

Visa signatur

6600K@4,5GHz 1,25V | EVGA 980Ti | Samsung 950 Pro m.2

Permalänk
Medlem
Skrivet av tomten_alle:

Jag använder dom lite omlott ja. Tanken var först att implementera en vettig variant i FIFOItem, för att sedan göra typ en wrapper för att passa uppgiftsbeskrivningen. Sedan har jag felsökt och strukturerat om till förbannelse, ofta sena kvällar under tidspress. Resulatet, precis som du säger, är inte optimalt. Dessutom försöker jag träna på rekursiva metoder.

Du har rätt att jag inte behöver gemföra storleken varje gång. Det blir mycket uträkningar i onödan. Jag behöver inte ens kolla om dom är tomma. Tack!

Jag måste tyvärr dekonstruera varje varv för att komma vidare. Min FIFOItem har möjlighet att göra på ett annat vis. Jag måste dock hålla mig till en viss tillhandahållen specifikation.

Vad menar du med mekanism som förhindrar att den skapar om sig själv? Allting sker väl per referens eftersom att det inte är primitiva datatyper? Jag tycker att det är lite otydligt när man inte sätter ut egna pekare, men det är väl en vanesak...

Det står ingenting i specen att du måste dekonstruera din kö vad jag kan se. Det står att du kan använda en Vector (jag skulle rekommendera en ArrayList eftersom FIFO ändå inte är synkroniserad) vilket skulle göra många delar av implementationen enklare, t ex isEmpty, size osv men även equals-metoden eftersom du inte behöver plocka isär något.

Visa signatur

Kom-pa-TI-bilitet

Permalänk
Skrivet av Teknocide:

Det står ingenting i specen att du måste dekonstruera din kö vad jag kan se. Det står att du kan använda en Vector (jag skulle rekommendera en ArrayList eftersom FIFO ändå inte är synkroniserad) vilket skulle göra många delar av implementationen enklare, t ex isEmpty, size osv men även equals-metoden eftersom du inte behöver plocka isär något.

Det här är roligare!

Om jag endast kan se det första objektet. Hur kan jag då gå vidare utan att plocka bort det första? Jag antar att jag inte kan utgå från att jag kommer att gemföra mot min egna FIFO?

Visa signatur

6600K@4,5GHz 1,25V | EVGA 980Ti | Samsung 950 Pro m.2

Permalänk
Medlem
Skrivet av tomten_alle:

Det här är roligare!

Om jag endast kan se det första objektet. Hur kan jag då gå vidare utan att plocka bort det första? Jag antar att jag inte kan utgå från att jag kommer att gemföra mot min egna FIFO?

Det är du som implementerar FIFO:n, du kan göra hur du vill. Även om du bara exponerar vissa funktioner, t ex first() och equals(), så har FIFO:n full tillgång till sin egen data internt om du designar den som så (vilket du verkligen borde göra).

Börja med att skriva ett interface så som du ser det i UML-diagrammet:

interface Queue { void add(Object item); void removeFirst(); Object first(); int maxSize(); ... osv }

När du gjort det skapar du din FIFO-klass och låter den implementera interfacet. För att representera en kö kan du använda en single-linked list ungefär som din FIFOItem såg ut fast simplare, den behöver i princip bara ha head- och tail-metoder där head returnerar värdet och tail returnerar en FIFOItem (vilken i sin tur har ett värde och en tail som kan ha ett värde, etc).

Låt sedan en intern variabel head i FIFO peka på den första FIFOItem som skapas (skapa den inte utanför klassen; du bör låta FIFOItem vara en inre privat klass). När du anropar removeFirst() sätter du helt enkelt FIFO-variabeln till FIFOItem.tail, så kommer garbage collectorn att ta hand om head-biten.

För att snabbt lägga till nya objekt i kön kan du ha ännu en variabel, end, som pekar på slutet av listan. När ett objekt läggs till med add skapas en ny FIFOItem som sätts till ends svans, sedan uppdaterar du end till att referera till sin egen svans. Nästan exakt som head ovan med andra ord.

Du kan även lägga till element i kön genom att iterera genom hela FIFOListan tills du kommer till sista elementet, och lägga till det där. Nackdelen med detta är att tiden för att lägga till ett element i kön växer tillsammans med längden av kön.

Visa signatur

Kom-pa-TI-bilitet

Permalänk

För att tråden ska ha någon mening så skriver jag in min slutgiltiga lösning också. Den är inte alls särskilt genomtänkt hela vägen och prestandan är inte heller på topp.

import java.util.NoSuchElementException; public class FIFO implements Queue { private boolean isFirst = true; private int maxSize = 0; private FIFO next = null; private Object storedObject = null; public FIFO() {} /* * Implementation of Queue */ public int size() { int size; if (this.isLast()) { size = 0; } else { size = 1 + this.getNext().size(); } this.maxSize(size); return size; } public int maxSize() { size(); return maxSize; } public boolean isEmpty() { if (this.size() == 0) { return true; } else { return false; } } public Object first() { if (this.isFirst() && this.isEmpty()) { throw new NoSuchElementException(); } else if (this.isFirst()) { return this.getNext().first(); } else { return this.getStoredObject(); } } public boolean equals(Object f) { if (f instanceof FIFO) { if (((FIFO) f).size() == this.size()) { if (this.hasNext()) { if (((FIFO) f).getStoredObject() == null || this.getStoredObject() == null) { if (((FIFO) f).getStoredObject() == null && this.getStoredObject() == null) { return ((FIFO) f).getNext().equals(this.getNext()); } } else if (((FIFO) f).getStoredObject().equals(this.getStoredObject())) { return ((FIFO) f).getNext().equals(this.getNext()); } } else if (this.isLast()) { if (((FIFO) f).getStoredObject() == null || this.getStoredObject() == null) { if (((FIFO) f).getStoredObject() == null && this.getStoredObject() == null) { return true; } } else if (((FIFO) f).getStoredObject().equals(this.getStoredObject())) { return true; } } } } return false; } public String toString() { if (this.isFirst() && this.isLast()) { return "Queue: "; } else if (this.isFirst) { return "Queue: " + String.valueOf(this.getNext()); } else if (this.hasNext()) { return "(" + String.valueOf(this.getStoredObject()) + ") " + String.valueOf(this.getNext()); } else { return "(" + String.valueOf(this.getStoredObject()) + ") "; } } public void add(Object item) { this.getLastFIFO().next = new FIFO(item); } public void removeFirst() { if (this.isLast()) { throw new NoSuchElementException(); } else if (this.getNext().hasNext()) { this.next = this.getNext().getNext(); } else { this.next = null; } } /* * From here only private methods */ private FIFO(Object storedObject) { this.isFirst = false; this.storedObject = storedObject; } private boolean hasNext() { if (this.next == null) { return false; } else { return true; } } private boolean isLast() { return !hasNext(); } private FIFO getNext() { if (this.isLast()) { return null; } else { return next; } } private Object getStoredObject() { return this.storedObject; } private boolean isFirst() { return isFirst; } private FIFO getLastFIFO() { if (this.isLast()) { return this; } else { return next.getLastFIFO(); } } private void maxSize(int size) { if (size > this.maxSize) { maxSize = size; } } }

Visa signatur

6600K@4,5GHz 1,25V | EVGA 980Ti | Samsung 950 Pro m.2

Permalänk
Medlem

Objekt i heapet är olika

För att jämföra två objekt som tillhör egen klass måste man implementera interface Comparable. Se exempel

class FIFOItem implements Comparable{
private int id;

int compareTo(Object o){
FIFOItem other = (FIFOItem)o

return id == other.id ? 0
: (id < other.id ? -1 : 1);
}
}

Observera att man kan amvända en av fältens annars används metoden hashCode(). Eftersom hashCode() metoden ger olika värd för olika instanser fick du false i jämförelse.
Observera att hashCode() är intager

Permalänk
Medlem
Skrivet av riemaxi:

För att jämföra två objekt som tillhör egen klass måste man implementera interface Comparable. Se exempel

Observera att man kan amvända en av fältens annars används metoden hashCode(). Eftersom hashCode() metoden ger olika värd för olika instanser fick du false i jämförelse.
Observera att hashCode() är intager

TS vill endast få reda på om två objekt är lika vilket gör Comparable onödigt då det är något man främst använder vid sortering av Collections.

Visa signatur

Spelrigg: 800D| i7 3930K@4,7 GHz - Custom WC | 32 GB Kingston HyperX Beast | 7970 GHz X-Edition |1x30 Dell U3011, 2x27" | Sennheiser HD650 | Xonar Essence STX |
Laptop: G74SX 17,3" 120 Hz 3D |
Server: Phenom II X4 955BE | Corsair XMS3 8 GB | 16 HDDs, 27 TB |
HTPCs: ASUS EEE Box 1.8 Ghz | Blu-Ray | OCZ Vertex 2 60 GB | 4 GB RAM |