istanza di Vs getClass ()


114

Vedo guadagno in termini di prestazioni durante l'utilizzo getClass()e ==operatore di sopra instanceOfdell'operatore.

Object  str = new Integer("2000");

long starttime = System.nanoTime();

if(str instanceof String) {
    System.out.println("its string");
} else {
    if (str instanceof Integer) {
        System.out.println("its integer");

    }
}

System.out.println((System.nanoTime()-starttime));

starttime = System.nanoTime();

if(str.getClass() == String.class) {
    System.out.println("its string in equals");
} else {
    if(str.getClass() == Integer.class) {
        System.out.println("its integer");
    }
}

System.out.println((System.nanoTime()-starttime));

C'è qualche linea guida, quale usare getClass()o instanceOf?

Dato uno scenario: So classi esatte da abbinare, cioè String, Integer(questi sono classi finali), etc.

Usare l' instanceOfoperatore è una cattiva pratica?



2
Il tuo metodo di temporizzazione causa ritardi artificiali e produce risultati di temporizzazione errati. Scambia l'ordine in cui esegui i controlli e vedrai che il primo controllo che fai (== o instanceof) sarà sempre più lungo. Immagino che sia il println () s. Non dovresti mai includere quella roba nel tuo blocco temporale.
kurtzmarc

Solo un commento a parte, per confrontare le prestazioni, utilizzare più cicli di iterazioni (ad esempio 10000) al fine di migliorare la precisione. Una singola invocazione non è una buona misura.
martins.tuga

Risposte:


140

Il motivo per cui le prestazioni di instanceofe getClass() == ...sono diverse è che stanno facendo cose diverse.

  • instanceofverifica se il riferimento all'oggetto sul lato sinistro (LHS) è un'istanza del tipo sul lato destro (RHS) o un sottotipo .

  • getClass() == ... verifica se i tipi sono identici.

Quindi il consiglio è di ignorare il problema delle prestazioni e utilizzare l'alternativa che ti dà la risposta di cui hai bisogno.

Usare l' instanceOfoperatore è una cattiva pratica?

Non necessariamente. Un uso eccessivo di uno instanceOfo più getClass() può essere "odore di design". Se non stai attento, ti ritroverai con un progetto in cui l'aggiunta di nuove sottoclassi si traduce in una notevole quantità di rielaborazione del codice. Nella maggior parte delle situazioni, l'approccio preferito è utilizzare il polimorfismo.

Tuttavia, ci sono casi in cui NON si tratta di "odore di design". Ad esempio, equals(Object)è necessario testare il tipo effettivo dell'argomento e restituirlo falsese non corrisponde. È meglio farlo usando getClass().


Termini come "buona pratica", "cattiva pratica", "odore di design", "antipattern" e così via dovrebbero essere usati con parsimonia e trattati con sospetto. Incoraggiano il pensiero in bianco e nero. È meglio esprimere i propri giudizi nel contesto, piuttosto che basarsi esclusivamente su dogmi; ad esempio qualcosa che qualcuno ha detto è "best practice".


@StephenC Come hai detto, è code smellda usare entrambi. Ciò significa che è una conseguenza di un codice di cattiva progettazione (non polimorfico) che ti fa usare entrambi. posso dedurre l'utilizzo di uno di loro in questo modo?
scambio eccessivo

@overexchange - 1) Ho detto "overuse" non "use". 2) A parte questo, non capisco cosa stai chiedendo. Cosa intendi per "dedurre l'utilizzo ..." ??? Il codice usa queste cose o non lo fa.
Stephen C

Ne deduco che l'uso di instanceof& getClass()entra in scena a causa di un cattivo design (non polimorfico) del codice. ho ragione?
scambio eccessivo

5
@overexchange - Non puoi inferire validamente che tutto l'uso di instanceof(per esempio) sia un cattivo design. Ci sono situazioni in cui può essere la soluzione migliore. Lo stesso per getClass(). Ripeto che ho detto "uso eccessivo" e non "uso" . Ogni caso deve essere giudicato in base ai suoi meriti ... non applicando ciecamente qualche regola dogmatica mal fondata.
Stephen C

44

Vuoi abbinare esattamente una classe , ad esempio solo la corrispondenza FileInputStreaminvece di qualsiasi sottoclasse di FileInputStream? In tal caso, utilizzare getClass()e ==. Di solito lo faccio in an equals, in modo che un'istanza di X non sia considerata uguale a un'istanza di una sottoclasse di X, altrimenti potresti incappare in complicati problemi di simmetria. D'altra parte, è più generalmente utile per confrontare che due oggetti appartengono alla stessa classe piuttosto che a una classe specifica.

Altrimenti, usa instanceof. Nota che con getClass()dovrai assicurarti di avere un riferimento non nullo con cui iniziare, altrimenti otterrai un NullPointerException, mentre instanceoftornerà solo falsese il primo operando è nullo.

Personalmente direi che instanceofè più idiomatica - ma usando uno di loro ampiamente è un odore di design nella maggior parte dei casi.


18

So che è passato un po 'di tempo da quando è stato chiesto, ma ieri ho imparato un'alternativa

Sappiamo tutti che puoi fare:

if(o instanceof String) {   // etc

ma cosa succede se non sai esattamente che tipo di classe deve essere? non puoi fare genericamente:

if(o instanceof <Class variable>.getClass()) {   

poiché dà un errore di compilazione.
Invece, ecco un'alternativa: isAssignableFrom ()

Per esempio:

public static boolean isASubClass(Class classTypeWeWant, Object objectWeHave) {

    return classTypeWeWant.isAssignableFrom(objectWeHave.getClass())
}

8
Non usare isAssignableFrom. Il modo corretto di scrivere o instanceof Stringusando la riflessione è String.getClass().isInstance(o). Il javadoc lo dice anche: questo metodo è l'equivalente dinamico dell'operatore del linguaggio Java instanceof.
Andreas

3

getClass () ha la restrizione che gli oggetti sono uguali solo ad altri oggetti della stessa classe, lo stesso tipo di runtime, come illustrato nell'output del codice seguente:

class ParentClass{
}
public class SubClass extends ParentClass{
    public static void main(String []args){
        ParentClass parentClassInstance = new ParentClass();
        SubClass subClassInstance = new SubClass();
        if(subClassInstance instanceof ParentClass){
            System.out.println("SubClass extends ParentClass. subClassInstance is instanceof ParentClass");
        }
        if(subClassInstance.getClass() != parentClassInstance.getClass()){
            System.out.println("Different getClass() return results with subClassInstance and parentClassInstance ");
        }
    }
}

Uscite:

Sottoclasse estende ParentClass. subClassInstance è instanceof ParentClass.

GetClass () diversi restituiscono risultati con subClassInstance e parentClassInstance.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.