web-dev-qa-db-fra.com

instance de Vs getClass ()

Je constate un gain de performance lorsque j'utilise les opérateurs getClass() et == Sur l'opérateur instanceOf.

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));

Existe-t-il des directives, lesquelles utiliser getClass() ou instanceOf?

Dans un scénario: je sais que les classes exactes doivent être mises en correspondance, c'est-à-dire String, Integer (ce sont des classes finales), etc.

L'utilisation de l'opérateur instanceOf est-elle une mauvaise pratique?

103
blob

La raison pour laquelle les performances de instanceof et de getClass() == ... est différente est qu’elles font des choses différentes.

  • instanceof teste si la référence de l'objet sur le côté gauche (LHS) est une instance du type sur le côté droit (RHS) ou un sous-type.

  • getClass() == ... vérifie si les types sont identiques.

Il est donc recommandé d'ignorer le problème de performances et d'utiliser l'alternative qui vous donne la réponse dont vous avez besoin.

Et oui, l’utilisation abusive de l’un ou l’autre d’entre eux peut être une "odeur de design". Si vous ne faites pas attention, vous vous retrouvez avec une conception dans laquelle l'ajout de nouvelles sous-classes entraîne un remaniement important du code. Dans la plupart des situations, l’approche privilégiée consiste à utiliser le polymorphisme.

Il y a des cas où ce ne sont pas des "odeurs de design". Par exemple, dans equals(Object), vous devez tester le type réel de l'argument et renvoyer false s'il ne correspond pas. Ceci est mieux fait en utilisant getClass().

129
Stephen C

Voulez-vous faire correspondre une classe exactement, par exemple. ne correspond que FileInputStream au lieu d'une sous-classe de FileInputStream? Si tel est le cas, utilisez getClass() et ==. Je le ferais généralement dans un equals, de sorte qu'une instance de X ne soit pas considérée comme égale à une instance d'une sous-classe de X - sinon, vous pourriez vous heurter à des problèmes de symétrie complexes. D'un autre côté, c'est plus généralement utile pour comparer deux objets de la classe identique à celle d'une classe spécifique.

Sinon, utilisez instanceof. Notez qu'avec getClass(), vous devrez vous assurer de disposer d'une référence non nulle pour commencer, sinon vous obtiendrez un NullPointerException alors que instanceof renverra simplement false si le premier opérande est nul.

Personnellement, je dirais que instanceof est plus idiomatique - mais utiliser soit = largement est une odeur de design dans la plupart des cas.

39
Jon Skeet

Je sais que cela fait un moment que cette question a été posée, mais j’ai appris une alternative hier

Nous savons tous que vous pouvez faire:

if(o instanceof String) {   // etc

mais que se passe-t-il si vous ne savez pas exactement quel type de classe il doit être? vous ne pouvez pas faire génériquement:

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

car cela donne une erreur de compilation.
Au lieu de cela, voici une alternative - isAssignableFrom ()

Par exemple:

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

    return classTypeWeWant.isAssignableFrom(objectWeHave.getClass())
}
18
Andy Dingfelder

getClass () a la restriction que les objets sont uniquement égaux aux autres objets de la même classe, du même type d'exécution, comme illustré dans le résultat du code ci-dessous:

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

Les sorties:

SubClass étend ParentClass. subClassInstance est instance of ParentClass.

Différents résultats de getClass () avec subClassInstance et parentClassInstance.

2
Saurav Sahu