Które z poniższych jest lepsze?
a instanceof B
lub
B.class.isAssignableFrom(a.getClass())
Jedyną różnicą, o której wiem, jest to, że gdy „a” jest zerowe, pierwsze zwraca false, a drugie zgłasza wyjątek. Poza tym, czy zawsze dają taki sam wynik?
java
instanceof
reflection
Megamug
źródło
źródło
Odpowiedzi:
Podczas korzystania
instanceof
musisz znać klasęB
w czasie kompilacji. Podczas korzystaniaisAssignableFrom()
może być dynamiczny i zmieniać się w czasie wykonywania.źródło
a instanceof Bref.getClass()
. jak może to być zaakceptowana odpowiedź z tak małym wyjaśnieniem (lub jej brakiem)?a instanceof Bref
nie jesta instanceof Bref.class
. Drugim argumentem dla operatora instanceof jest nazwa klasy, a nie wyrażenie rozstrzygające instancję obiektu klasy.B.class.isAssignableFrom(a.getClass())
B jest znane ia instanceof B
jest lepsze. Dobrze?instanceof
może być używany tylko z typami referencyjnymi, a nie pierwotnymi.isAssignableFrom()
może być używany z dowolnymi obiektami klasy:Widzieć http://java.sun.com/javase/6/docs/api/java/lang/Class.html#isAssignableFrom(java.lang.Class) .
źródło
Mówienie w kategoriach wydajności:
TL; DR
Użyj isInstance lub instanceof, które mają podobną wydajność. isAssignableFrom jest nieco wolniejszy.
Posortowane według wydajności:
Oparty na teście 2000 iteracji na JAVA 8 Windows x64, z 20 iteracjami rozgrzewania.
W teorii
Korzystając z miękkiej przeglądarki kodu bajtowego , możemy przetłumaczyć każdego operatora na kod bajtowy.
W kontekście:
JAWA:
Kod bajtowy:
JAWA:
Kod bajtowy:
JAWA:
Kod bajtowy:
Mierząc liczbę instrukcji kodu bajtowego używanych przez każdego operatora, można oczekiwać, że instanceof i isInstance będą szybsze niż isAssignableFrom . Rzeczywista wydajność NIE jest jednak określana przez kod bajtowy, ale przez kod maszynowy (zależny od platformy). Zróbmy mikro test porównawczy dla każdego operatora.
Benchmark
Credit: Zgodnie z zaleceniami @ aleksandr-dubinsky i dzięki @yura za dostarczenie kodu podstawowego, oto test porównawczy JMH (zobacz ten przewodnik strojenia ):
Dał następujące wyniki (wynik to liczba operacji w jednostce czasu , więc im wyższy wynik, tym lepiej):
Ostrzeżenie
instanceof
w kontekście twojego kodu może zostać zoptymalizowany łatwiej niżisInstance
na przykład ...Aby podać przykład, wykonaj następującą pętlę:
Dzięki JIT kod jest w pewnym momencie optymalizowany i otrzymujemy:
Uwaga
Pierwotnie ten post przeprowadzał własny test porównawczy przy użyciu pętli for w surowej JAVA, co dawało niewiarygodne wyniki, ponieważ niektóre optymalizacje, takie jak Just In Time, mogą wyeliminować pętlę. Więc głównie mierzyło to, ile czasu zajął kompilatorowi JIT, aby zoptymalizować pętlę: zobacz Test wydajności niezależny od liczby iteracji, aby uzyskać więcej szczegółów
Powiązane pytania
źródło
instanceof
to kod bajtowy, który używa zasadniczo tej samej logiki cocheckcast
(kod bajtowy za rzutowaniem). Z natury będzie szybszy niż inne opcje, niezależnie od stopnia optymalizacji JITC.isAssignableFrom()
dynamiczne.Bardziej bezpośredni odpowiednik
a instanceof B
toTo działa (zwraca false), gdy
a
jestnull
zbyt.źródło
Poza podstawowymi różnicami wspomnianymi powyżej, istnieje zasadnicza subtelna różnica między instancją operatora a metodą isAssignableFrom w klasie.
Czyta się
instanceof
jako „czy to (lewa część) jest wystąpieniem tej lub dowolnej podklasy tego (prawa część)” i czyta sięx.getClass().isAssignableFrom(Y.class)
jako „Czy mogę pisaćX x = new Y()
”. Innymi słowy, operator instanceof sprawdza, czy lewy obiekt jest taki sam lub podklasę prawej klasy, podczas gdyisAssignableFrom
sprawdza, czy możemy przypisać obiekt klasy parametru (od) do odwołania do klasy, na której wywoływana jest metoda.Zauważ, że oba rozważają rzeczywistą instancję, a nie typ odwołania.
Rozważ przykład 3 klas A, B i C, w których C rozszerza B, a B rozszerza A.
źródło
b instanceof A
jest równoważneA.class.isAssignableFrom(b.getClass())
(jak zauważył PO). Twój przykład jest poprawny, ale nieistotny.new Y()
może nie być legalne, jeśliY
jest abstrakcyjne lub bez publicznego domyślnego konstruktora, możesz powiedzieć, żeX x = (Y)null
jest legalne, jeśli i tylko jeślix.getClass().isAssignableFrom(Y.class)
jest prawdziwe.Jest jeszcze jedna różnica:
zerowa instancja X
false
nie ma znaczenia, czym jest Xnull.getClass (). isAssignableFrom (X) zgłosi wyjątek NullPointerException
źródło
null instanceof X
(gdzie X jest klasą znaną w czasie kompilacji) zawsze zwrócifalse
.X.class.isAssignableFrom(null.getClass())
, prawda? Ale tak, wywołaniegetClass()
zerowego odwołania spowoduje NPE.getClass()
nie należy go używać zisAssignableFrom
- operacja jest przeznaczona do sytuacji, gdy nie ma żadnych obiektów. Jeśli masz odwołanie do obiektua
, wykorzystywaniaa instanceof SomeClass
(jeśli zrobić znać typSomeClass
) lubsomeObject.getClass().isInstance(a)
(jeśli nie wiesz, rodzajsomeObject
).Jest jeszcze jedna różnica. Jeśli typ (klasa) do testowania jest dynamiczny, np. Przekazany jako parametr metody, instanceof nie wycina go za ciebie.
ale możesz zrobić:
Ups, widzę, że ta odpowiedź jest już omówiona. Może ten przykład jest komuś pomocny.
źródło
this
),clazz.isInstance(this)
byłoby lepiej w twoim przykładzie.Ten wątek dał mi wgląd w to, czym się
instanceof
różniłisAssignableFrom
, więc pomyślałem, że podzielę się czymś własnym.Odkryłem, że używanie
isAssignableFrom
jest jedynym (prawdopodobnie nie jedynym, ale być może najłatwiejszym) sposobem, aby zapytać siebie, czy odwołanie do jednej klasy może mieć instancje innej, gdy nie ma instancji żadnej klasy do porównania.Dlatego też nie znalazłem używania
instanceof
operatora do porównywania możliwości przypisania jako dobrego pomysłu, gdy wszystko, co miałem, to klasy, chyba że rozważałem utworzenie instancji z jednej z klas; Myślałem, że to będzie niechlujne.źródło
instanceof nie może być używany z typami pierwotnymi ani typami ogólnymi. Jak w poniższym kodzie:
Błąd jest następujący: Nie można wykonać instancji sprawdzenia względem parametru typu T. Zamiast tego należy użyć obiektu Erasure Object, ponieważ dalsze ogólne informacje o typie zostaną usunięte w czasie wykonywania.
Nie kompiluje się z powodu usunięcia typu usuwającego odwołanie do środowiska wykonawczego. Jednak poniższy kod zostanie skompilowany:
źródło
Rozważ następującą sytuację. Załóżmy, że chcesz sprawdzić, czy typ A jest superklasą typu obj, możesz przejść albo
... A.class.isAssignableFrom (obj.getClass ()) ...
LUB
... obj instanceof A ...
Ale rozwiązanie isAssignableFrom wymaga, aby tutaj był widoczny typ obj. Jeśli tak nie jest (np. Typ obj może być prywatnej klasy wewnętrznej), ta opcja jest niedostępna. Jednak rozwiązanie instanceof zawsze będzie działać.
źródło
obj
w tym przykładzie) dowolnego typu , możesz wywołać publicznągetClass()
metodę, aby uzyskać metadane odbicia dla klasy implementującej. Jest to prawdą, nawet jeśli ten typ klasy implementującej nie byłby prawnie widoczny w tym miejscu podczas kompilacji. Jest OK przy starcie, ponieważ, aby utrzymaćobj
odniesienia, niektóre ścieżki kodu, który ostatecznie nie mają legalny dostęp do klasy stworzył jedną i dał (wyciekły?) Go do ciebie.Powyższy pseudo kod jest definicją, jeżeli referencje typu / klasy A można przypisać z referencji typu / klasy B. Jest to definicja rekurencyjna. Dla niektórych może to być pomocne, dla innych może być mylące. Dodaję to na wypadek, gdyby ktoś uznał to za przydatne. To tylko próba uchwycenia mojego zrozumienia, to nie jest oficjalna definicja. Jest używany w pewnej implementacji Java VM i działa dla wielu przykładowych programów, więc chociaż nie mogę zagwarantować, że przechwytuje wszystkie aspekty isAssignableFrom, nie jest całkowicie wyłączony.
źródło
Mówiąc w kategoriach wydajności „2” (z JMH):
To daje:
Abyśmy mogli dojść do wniosku: instanceof tak szybko, jak isInstance () i isAssignableFrom () nie daleko (+ 0,9% czasu wykonania). Więc nie ma żadnej różnicy, którą wybierzesz
źródło
Co powiesz na kilka przykładów pokazujących to w akcji ...
źródło
niektóre testy, które przeprowadziliśmy w naszym zespole, pokazują, że
A.class.isAssignableFrom(B.getClass())
działa szybciej niżB instanceof A
. może to być bardzo przydatne, jeśli chcesz to sprawdzić na dużej liczbie elementów.źródło
instanceof
, uważam, że masz poważne problemy projektowe ...