instancja Vs getClass ()


114

Widzę wzrost wydajności podczas używania getClass()i ==operatora nad instanceOfoperatorem.

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

Czy istnieją jakieś wytyczne, który z nich korzystać getClass()lub instanceOf?

Biorąc pod uwagę scenariusz: Wiem dokładnie dopasowane do klas, to znaczy String, Integer(są to zajęcia końcowe), etc.

Czy używanie instanceOfoperatora jest złą praktyką?



2
Twoja metoda pomiaru czasu powoduje sztuczne opóźnienia i daje nieprawidłowe wyniki. Zamień kolejność sprawdzania, a zobaczysz, że pierwsza przeprowadzona kontrola (== lub instanceof) będzie zawsze dłuższa. Myślę, że to println () s. Nigdy nie powinieneś włączać tych rzeczy do swojego bloku czasowego.
— kurtzmarc

Tylko jeden komentarz od siebie, aby porównać wydajność, użyj wielu iteracji cykli (np. 10000) w celu zwiększenia dokładności. Jedno wezwanie nie jest dobrym środkiem.
— martins.tuga

Odpowiedzi:


140

Powodem, dla którego wydajność instanceofi getClass() == ...jest inna, jest to, że robią różne rzeczy.

  • instanceofsprawdza, czy odwołanie do obiektu po lewej stronie (LHS) jest wystąpieniem typu po prawej stronie (RHS), czy jakimś podtypem .

  • getClass() == ... sprawdza, czy typy są identyczne.

Dlatego zalecamy zignorowanie problemu z wydajnością i skorzystanie z alternatywy, która daje odpowiedź, której potrzebujesz.

Czy używanie instanceOfoperatora jest złą praktyką?

Niekoniecznie. Nadużywanie któregokolwiek z nich instanceOflub getClass() może oznaczać „zapach projektu”. Jeśli nie będziesz ostrożny, otrzymasz projekt, w którym dodanie nowych podklas powoduje znaczną ilość przeróbek kodu. W większości sytuacji preferowanym podejściem jest użycie polimorfizmu.

Jednak są przypadki, w których NIE są to „zapachy projektu”. Na przykład, equals(Object)musisz przetestować rzeczywisty typ argumentu i zwrócić, falsejeśli nie pasuje. Najlepiej to zrobić za pomocą getClass().


Pojęcia takie jak „najlepsza praktyka”, „zła praktyka”, „zapach projektu”, „anty-wzór” itd. Powinny być używane oszczędnie i traktowane z podejrzliwością. Zachęcają do czarno-białego myślenia. Lepiej jest wydawać sądy w kontekście, niż opierać się wyłącznie na dogmacie; np. coś, co ktoś powiedział, jest „najlepszą praktyką”.


@StephenC Jak powiedziałeś, jest code smellto użycie albo. Oznacza to, że jest to konsekwencja złego projektu (niepolimorficznego) kodu, który zmusza cię do użycia. czy mogę w ten sposób wywnioskować użycie któregokolwiek z nich?
— przewyższenie

@overexchange - 1) Powiedziałem „nadużywanie”, a nie „używanie”. 2) Poza tym nie rozumiem, o co pytasz. Co masz na myśli, mówiąc „wnioskuj użycie ...” ??? Kod albo używa tych rzeczy, albo nie.
— Stephen C

Wnioskuję z tego, że użycie instanceof& getClass()pojawia się z powodu istniejącego złego projektu (niepolimorficznego) kodu. mam rację?
— przewymiarowanie

5
@overexchange - nie można zasadnie wywnioskować, że każde użycie instanceof(na przykład) jest złym projektem. Są sytuacje, w których może to być najlepsze rozwiązanie. To samo dotyczy getClass(). Powtórzę, że powiedziałem „nadużywać”, a nie „używać” . Każdy przypadek należy oceniać merytorycznie ... a nie ślepo stosując jakąś nieuzasadnioną dogmatyczną zasadę.
— Stephen C

44

Czy chcesz dokładnie dopasować klasę , np. Tylko dopasowywanie FileInputStreamzamiast dowolnej podklasy FileInputStream? Jeśli tak, użyj getClass()i ==. Zazwyczaj robiłbym to w an equals, więc wystąpienie X nie jest uważane za równe wystąpieniu podklasy X - w przeciwnym razie możesz dostać się do trudnych problemów z symetrią. Z drugiej strony jest to bardziej przydatne do porównywania, że ​​dwa obiekty należą do tej samej klasy niż jednej określonej klasy.

W przeciwnym razie użyj instanceof. Zauważ, getClass()że będziesz musiał upewnić się, że masz niezerowe odniesienie, od którego zaczniesz, w przeciwnym razie otrzymasz a NullPointerException, podczas gdy instanceofzwróci po prostu, falsejeśli pierwszy operand ma wartość null.

Osobiście powiedziałbym, że instanceofjest bardziej idiomatyczny - ale intensywne używanie któregokolwiek z nich jest w większości przypadków zapachem projektowym.


18

Wiem, że minęło trochę czasu, odkąd o to zapytano, ale wczoraj nauczyłem się alternatywy

Wszyscy wiemy, że możesz:

if(o instanceof String) {   // etc

ale co, jeśli nie wiesz dokładnie, jaki to rodzaj zajęć? nie możesz generalnie zrobić:

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

ponieważ daje błąd kompilacji.
Zamiast tego tutaj jest alternatywa - isAssignableFrom ()

Na przykład:

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

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

8
Nie używaj isAssignableFrom. Prawidłowy sposób pisania o instanceof Stringza pomocą refleksji to String.getClass().isInstance(o). Tak mówi javadoc: ta metoda jest dynamicznym odpowiednikiem instanceofoperatora języka Java .
— Andreas

3

getClass () ma ograniczenie, że obiekty są równe tylko innym obiektom tej samej klasy, tego samego typu w czasie wykonywania, jak pokazano na wyjściu poniższego kodu:

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

Wyjścia:

SubClass rozszerza ParentClass. subClassInstance jest instancją ParentClass.

Różne wyniki funkcji getClass () zwracają z subClassInstance i parentClassInstance.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.