Permalänk

Jämföra objekttyp i java

Hur kan man jämföra objekttyper med varann i Java? Man kan ju väldigt lätt se om b är av klassen Bil med b instanceof Bil , men hur gör man om man vill se om två objekt är instanser av samma klass? Något i still med b instanceof c.getClass() , men det funkar ju självklart inte...

Visa signatur

e6600@3.2GHz@1.35v + P5B deluxe + corsair 2gb pc6400 + HD4350 m.m.

Permalänk

Är detta ett giltigt sätt:
a.getClass().equals(b.getClass())

Visa signatur

e6600@3.2GHz@1.35v + P5B deluxe + corsair 2gb pc6400 + HD4350 m.m.

Permalänk
Medlem

Det fungerar, givet att a != null och b != null (annars kastas ett NullPointerException). Du kan också använda == istället för equals(), eftersom ett equals()-anrop på en Class-instans i själva verket anropar Object.equals(), som är definierad så här:

public boolean equals(Object obj) { return (this == obj); }

Anledningen till att det fungerar är att klassladdaren bara skapar en Class-instans för varje klass som laddas. Så har du två instanser av Bil, bil1 och bil2, och anropar getClass() på båda, så kommer de att peka till samma Class-instans, och bil1.getClass() == bil2.getClass().

Frågan är varför du vill göra den här kollen? Det faktum att du alls tycker dig behöva den skvallrar om bristfällig design...

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av badboll
Det fungerar, givet att a != null och b != null (annars kastas ett NullPointerException). Du kan också använda == istället för equals(), eftersom ett equals()-anrop på en Class-instans i själva verket anropar Object.equals(), som är definierad så här:

public boolean equals(Object obj) { return (this == obj); }

Anledningen till att det fungerar är att klassladdaren bara skapar en Class-instans för varje klass som laddas. Så har du två instanser av Bil, bil1 och bil2, och anropar getClass() på båda, så kommer de att peka till samma Class-instans, och bil1.getClass() == bil2.getClass().

Frågan är varför du vill göra den här kollen? Det faktum att du alls tycker dig behöva den skvallrar om bristfällig design...

(Jag använder i min text variablerna bil1 och bil2 istället för a och b)

Tjo!

Efter som du bemödat dig att skriva så mycket detaljer så passar jag på att fylla ut med lite extrainformation också.

Medans du har rätt med att det i det här fallet går att använda jämförelseoperatorn också (==) så skulle jag nog helst försöka undvika att nämna det då det komplicerar livet för någon som är ny på Java. Jag tycker det är ett bättre råd att försöka använda equals här för att vara konsistent med hur man jämför objekt i vanliga fall. Håller du inte med?

Sedan bara för att hänga upp sig på smådetaljer så behöver bara bil1 vara icke null för att unvdika ett null pointer exception. Dvs gör man bil1.equals(null) så får man resultatet false. Konventionen är att en equals-metod ska kunna hantera null som inargument.

För att vara ytterligare petiga så behöver faktiskt inte ditt påstående "har du två instanser av Bil, bil1 och bil2, och anropar getClass() på båda, så kommer de att peka till samma Class-instans" vara sant. Nu förstår jag att det här är rejäl överkurs för de flesta men då vi ändå pratar om detaljer så är det lika bra att ta upp dem. Det är i Java möjligt att ladda två varianter (eller) samma av klassen bil i olika klassladdare och sedan i vissa luriga fall få bil1 och bil2 att båda inte vara null och bestå av objekt av klassen Bil men däremot ha fallet där bil1.getClass() != bil2.getClass(). De som har arbetat med lite mer avancerade projekt i JBoss brukar tyvärr ofta bli bekanta med detta fenomen då man redeployar om delar av en applikation och då den nya delen får en ny klassladdare.

Det är inte alls bristfällig design att han skulle vilja ha reda på exakt vilket objekt det är. Det kan i vissa fall absolut det man vill. Vi har ju redan tagit upp ett exempel där man troligtvis vill ha det så, nämligen i equals()-metoden. Det är tyvärr inte ovanligt att man hittar en equals()-metod som ser ut här

// TRASIG SNIPPET! ANVÄND INTE I VERKLIGA LIVET! public boolean equals(Object obj) { if (obj == null) { return false }; //Ifall det inte är en bil, avsluta if ( !(obj instanceof Bil)) { return false; } //Gör jämförelsekoll här och returnera true/false }

Tyvärr så kan ju det där bli otroligt fel. Om man nu skulle ha en subklass som heter LastBil så skulle det kunna bli så att bil1.equals(lastbil1) skulle kunna bli sant om lastbilen hade samma egenskaper som en bil. Fast vi båda är nog överens om att trots att lastbilen kanske har fyra hjul och de egenskaper som finns på bilen så är de inte lika så länge lastbilen är klassad som en utökad bil.

Fast även proffsen gör ju fel. I java.util.Date så gjorde Sun misstaget att göra en instanceof istället för klass-koll vilket gör att följande lilla snippet blir väldigt märkligt nog sant.

java.util.Date date = new java.util.Date(123456); java.sql.Timestamp timestamp = new java.sql.Timestamp(123456); timestamp.setNanos(456789000); System.out.println("De två objekten är lika: "+date.equals(timestamp));

Då de dock är väldigt måna om bakåtkompabilitet så kan de inte ändra detta beteende, även om det är ett dåligt sådant.

Som sagt, ville bara fylla ut med lite ytterligare information jag också när vi ändå är i farten.

//C

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av conio
Medans du har rätt med att det i det här fallet går att använda jämförelseoperatorn också (==) så skulle jag nog helst försöka undvika att nämna det då det komplicerar livet för någon som är ny på Java. Jag tycker det är ett bättre råd att försöka använda equals här för att vara konsistent med hur man jämför objekt i vanliga fall. Håller du inte med?

Jag tror för min del att om TS är kunnig nog att ställa berörd fråga, så är han kunnig nog att inte förvirras alltför mycket av att ges hela sanningen. Antingen underskattar du TS eller så överskattar jag densamma...
Ibland är man faktiskt intresserad om två variabler pekar mot samma instans, och då är ju == ett bättre val. Dock bör man ha för vana att kommentera jämförelsen, att man vet vad man gör, så det står helt klart vad man hade för avsikt.

Citat:

Sedan bara för att hänga upp sig på smådetaljer så behöver bara bil1 vara icke null för att unvdika ett null pointer exception. Dvs gör man bil1.equals(null) så får man resultatet false. Konventionen är att en equals-metod ska kunna hantera null som inargument.

Helt rätt, jag slarvade.

Citat:

För att vara ytterligare petiga så behöver faktiskt inte ditt påstående "har du två instanser av Bil, bil1 och bil2, och anropar getClass() på båda, så kommer de att peka till samma Class-instans" vara sant. Nu förstår jag att det här är rejäl överkurs för de flesta men då vi ändå pratar om detaljer så är det lika bra att ta upp dem. Det är i Java möjligt att ladda två varianter (eller) samma av klassen bil i olika klassladdare och sedan i vissa luriga fall få bil1 och bil2 att båda inte vara null och bestå av objekt av klassen Bil men däremot ha fallet där bil1.getClass() != bil2.getClass().

Jag trodde också det (och var på väg att skriva en liknande grej om olika klassladdare), tills jag gjorde en liten testapplikation nedan (som väl borde använda två olika klassladdare?)... och nu blev jag med ens osäker...

public class Main { public static void main(String[] args) throws Exception { ClassLoader loaderOne = ClassLoader.getSystemClassLoader(); ClassLoader loaderTwo = new java.net.URLClassLoader(new java.net.URL[0], null); Class<?> a = loaderOne.loadClass("java.lang.String"); Class<?> b = loaderTwo.loadClass("java.lang.String"); System.out.println("loaderOne == loaderTwo ? " + (loaderOne == loaderTwo)); System.out.println("a == b ? " + (a == b)); } }

Output:

loaderOne == loaderTwo ? false a == b ? true

Vad händer här, som jag inte begriper?

Citat:

Det är inte alls bristfällig design att han skulle vilja ha reda på exakt vilket objekt det är.

I de allra flesta fall vill folk som söker dylika lösningar egentligen ha någon form av polymorfism istälet för en exakt typkontroll, därav min fråga till TS. Men vad vet jag, nu kanske det är jag som underskattar honom?

Permalänk
Medlem
Citat:

Ursprungligen inskrivet av badboll
Jag trodde också det (och var på väg att skriva en liknande grej om olika klassladdare), tills jag gjorde en liten testapplikation nedan (som väl borde använda två olika klassladdare?)... och nu blev jag med ens osäker...

Inte osäker längre. I mitt exempel laddas klassen (java.lang.String) i ett tidigare stadium av den s.k. bootstrap-klassladdaren, och klassen laddas uppenbarligen inte om i mina loadClass()-anrop. Gott så, ordningen återställd och jag kan sova i natt...