2012-05-05 13 views
21

Es müssen zwei Objekte basierend auf der implementierten Klasse verglichen werden? Wann zu vergleichen mit getClass() und wenn getClass().getName()? Gibt es einen Unterschied zwischen diesen Ansätzen, um zwei Objektklassen (Namen) zu vergleichen?Vergleichen zweier Klassen anhand ihrer Typen oder Klassennamen

public abstract class Monster { ... } 
public class MonsterTypeOne extends Monster { ... } 
public class MonsterTypeTwo extends Monster { ... } 

    Monster monster = MonsterTypeOne(); 
    Monster nextMonster = MonsterTypeTwo(); 


if(nextMonster.getClass().getName().equals(monster.getClass().getName()))// #1 

if(nextMonster.getClass().equals(monster.getClass()))// #2 

EDIT 1


Was?

nextMonster.getClass().equals(MonsterTypeOne.class) 
+0

Haben Sie .equals mit getClass benötigen? Get class gibt ein Nicht-String-Objekt zurück, das ich glaube. +1 interessante Frage. – jmort253

Antwort

18

Gibt es einen Unterschied zwischen diesen nähert sich zwei Objekte Klassentypen (Namen) zu vergleichen?

Ja. Zwei Klassen können denselben Namen haben, wenn sie von verschiedenen ClassLoader s geladen werden.

"The basics of Java class loaders" sagt

In seiner einfachsten Form, ein Class Loader einen flachen Namensraum der Klasse Körper erzeugt, die durch einen string name referenziert werden.

"Eclipse - a tale of two VMs (and many classloaders)" sagt

dass es möglich ist, bedeutet zwei Klassen mit dem gleichen Namen in eine VM auf einmal geladen haben, vorausgesetzt, sie verfügen über zwei separate Classloader


Wann zu vergleichen mit getClass() und wenn getClass().getName()?

Wenn Sie wissen wollen, ob zwei Objekte vom gleichen Typ sind Sie die equals Methode verwenden, sollten die beiden Klassen zu vergleichen - die erste Option.

Ich kann mir nicht vorstellen, warum Sie das tun möchten, aber wenn Sie wissen möchten, ob zwei Objekte mit verschiedenen konkreten Typen Typen mit demselben voll qualifizierten Namen haben, dann könnten Sie die zweite verwenden. Wenn Sie im Java-Kontext "konkrete Typen" und "voll qualifizierte Namen" nicht verstehen, schreiben Sie keinen Typanalyse-Code für Java, damit Sie nicht möchten.

28

Verwendung class.equals():

if (nextMonster.getClass().equals(monster.getClass())) 

oder, weil jede Klasse wie ein Singleton ist - es gibt nur eine Instanz jeder Klasse pro JVM - Sie können sogar eine Identität Vergleich verwenden:

if (nextMonster.getClass() == monster.getClass()) 
3

I lief auf ein Problem beim Vergleich von zwei Klassen mit .equals. Die oben angegebene Lösung ist nicht vollständig genau. Klasse implementiert Comparable nicht.

Klassenverweise sind nicht unbedingt echte Singletons in einer JVM, da Sie mehrere ClassLoader verwenden können.

Ich schrieb ein Maven-Plugin, das nach dem Kompilieren Anmerkungen aus Beans graben sollte. Das Plugin hatte einen Classloader und ich hatte meinen eigenen Classloader. Wenn zwei Klassen desselben Namens von verschiedenen Ladevorrichtungen verglichen werden, würde der Vergleich fehlschlagen.

Die Implementierung von Object.equals sieht wie folgt aus:

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

So finden Sie den Vergleich Referenzen werden.

Wenn Sie Klassen zu vergleichen und Sie wissen sicher, dass es nur einen geben Classloader beteiligt Sie sicher .equals oder c1 == c2 verwenden können, aber wenn Sie nicht sicher sind, sollten Sie mit dem Namen vergleichen:

if(c1.getName().equals(c2.getName()) { 
    ... 
} 
+0

Warum sollten Sie Klassennamen von zwei verschiedenen Klassenladern vergleichen? Ist das ein gültiger Senario? Gib mir ein Beispiel, wenn du das im richtigen Leben machen musst. –

+0

Meine Bewerbung war sehr ungewöhnlich. Ich machte ein Maven-Plugin, das Dokumentation für REST-Endpunkte generiert. Ich wollte die JAX-Annotationen (oder Spring) verwenden, um HTML-Dokumente zu generieren. Das verwendete Maven-Plugin lädt alle Klassen mit der JarClassLoader-Klasse und das Maven-Plugin führt seinen Code im Classloader des Builds aus. Ich habe versucht zu sehen, ob die Annotation in der Jar-Klasse vorhanden war, aber der Vergleich ist fehlgeschlagen, obwohl sie die gleichen Klassennamen waren. Ich habe das Projekt aufgegeben. –

1

Tatsächlich ist der Vergleich der vertrauenswürdigen Klasse mit dem Namen eine Schwäche. https://cwe.mitre.org/data/definitions/486.html

if (nextMonster.getClass() == monster.getClass()) 

zu finden ist der richtige Weg, Klassen vergleichen

if (nextMonster.getClass().equals(monster.getClass())) 

noch aus dem gleichen Grunde sollte funktionieren @Bohemian

erwähnt
0

Eine andere Möglichkeit, das gleiche zu erreichen durch zwingende hashcode wird in Unterklasse.

public interface Parent { 
} 

public static class Child1 implements Parent{ 
    private String anyfield="child1"; 

    @Override 
    public int hashCode() { 
     //Code based on "anyfield" 
    } 

    @Override 
    public boolean equals(Object obj) { 
     //equals based on "anyfield" 
    } 
} 

public static class Child2 implements Parent{ 
    private String anyfield="child2"; 

    @Override 
    public int hashCode() { 
     //Code based on "anyfield" 
    } 

    @Override 
    public boolean equals(Object obj) { 
     //equals based on "anyfield" 
    } 
} 

Jetzt wird der equals zurückgegeben, wenn Implementierungen/Unterklassen vom gleichen konkreten Typ sind.

public static void main(String args[]){ 
    Parent p1=new Child1(); 
    Parent p2=new Child1(); 
    Parent p3=new Child2(); 
    System.out.println("p1 and p2 are same : "+p1.equals(p2)); 
    System.out.println("p2 and p3 are same : "+p2.equals(p3)); 
} 

Output-

p1 and p2 are same : true 
p2 and p3 are same : false 
Verwandte Themen