2012-05-05 18 views
21

È necessario confrontare due oggetti in base alla classe che implementano? Quando confrontare usando getClass() e quando getClass().getName()? C'è qualche differenza tra questo approccio per confrontare due tipi di classi di Oggetti (nomi)?Confronto di due classi in base al tipo o al nome della classe

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


Che dire:?

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

Avete bisogno .equals con getClass? Ottieni resi di classe un oggetto non String che io credo. +1 domanda interessante. – jmort253

risposta

18

v'è alcuna differenza tra questo approcci per confrontare i tipi di due oggetti di classe (nomi)?

Sì. Due classi possono avere lo stesso nome se sono caricate da diversi ClassLoader s.

"The basics of Java class loaders" dice

Nel caso più semplice, un caricatore di classe crea uno spazio nome semplice dei corpi di classe a cui fa riferimento un nome di stringa.

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

Ciò significa che è possibile avere due classi con lo stesso nome caricato in una macchina virtuale contemporaneamente, purché abbiano due ClassLoader distinte


Quando confrontare usando getClass() e quando getClass().getName()?

Se vuoi sapere se due oggetti sono dello stesso tipo si dovrebbe utilizzare il metodo equals per confrontare le due classi - la prima opzione.

Non riesco a immaginare perché vorresti farlo, ma se vuoi sapere se due oggetti con tipi diversi di calcestruzzo hanno tipi con lo stesso nome completo, potresti usare il secondo. Se non si capiscono "tipi concreti" e "nomi completi" nel contesto di Java, non si scrive codice di analisi del tipo per java, quindi non si desidera.

28

Uso class.equals():

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

o, perché ogni classe è come un Singleton - non c'è una sola istanza di ogni Classe per JVM - si può anche utilizzare un confronto di identità:

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

I si è imbattuto in un problema nel confrontare due classi usando .equals. La soluzione sopra fornita non è completamente accurata. La classe non implementa Comparabile.

I riferimenti di classe non sono necessariamente veri singleton all'interno di una JVM perché è possibile avere più ClassLoader.

Stavo scrivendo un plug-in Maven che stava scavando le annotazioni dai fagioli dopo la compilazione. Il plugin aveva un classloader e io avevo il mio proprio classloader. Confrontando due classi con lo stesso nome da caricatori diversi, il confronto fallirebbe.

L'attuazione di Object.equalsQ assomiglia a questo:

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

riferimenti Così sarete confrontando.

Se si confrontano le classi e si sa per certo ci sarà solo un programma di caricamento classe coinvolti si può tranquillamente utilizzare .equals o c1 == c2, ma se non si è sicuri si devono confrontare per nome:

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

perché dovresti confrontare i nomi di classe di due differnt classloader? È un senario valido? Fammi un esempio quando hai bisogno di farlo nella vita reale. –

+0

La mia applicazione era molto insolita. Stavo creando un plugin Maven che genera documentazione per endpoint REST. Volevo usare le annotazioni JAX (o Spring) per generare documenti HTML. Il plugin Maven usato caricava tutte le classi usando la classe JarClassLoader e il plugin Maven eseguiva il suo codice nel classloader della build. Stavo cercando di vedere se l'annotazione era presente nella classe Jar, ma il confronto non è riuscito anche se erano gli stessi nomi di classe. Ho finito per abbandonare il progetto. –

1

In effetti confrontare la classe fidata per nome è un punto debole. consultare https://cwe.mitre.org/data/definitions/486.html

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

è il modo corretto per confrontare classi

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

dovrebbe funzionare per lo stesso motivo citato @Bohemian

0

Un altro modo per ottenere lo stesso sarà ridefinendo codice hash in sottoclasse.

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" 
    } 
} 

Ora gli equali ritorneranno se le implementazioni/sottoclassi sono dello stesso tipo concreto.

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 
Problemi correlati