Do czego służy operator „instanceof” w Javie?

163

Do czego służy instanceofoperator? Widziałem takie rzeczy

if (source instanceof Button) {
    //...
} else {
    //...
}

Ale nic z tego nie miało dla mnie sensu. Zrobiłem swoje badania, ale wymyśliłem tylko przykłady bez żadnych wyjaśnień.

Ben
źródło
38
Nie ma nic złego w zadawaniu pytań, ale jeśli uczysz się języka Java, możesz chcieć kupić książkę. Każda porządna książka o Javie zawierałaby odpowiedź na to pytanie i następne 1000, które będziesz mieć.
Prezydent James K. Polk,
Taki operator ma wiele specyficznych zastosowań. To byłoby konkretne pytanie, gdyby prosiło o wyjaśnienie jednego z przykładów, które nie miały dla ciebie sensu.
Raedwald
2
Poniższe odpowiedzi są poprawne, jednak zauważ, że instanceof jest nadużywanym operatorem 9 razy na 10 można go zastąpić odpowiednim użyciem polimorfizmu (nie zawsze, ale często)
Richard Tingle
Poszedłbym o jeden dalej niż Richard: NIGDY nie widziałem prawidłowego użycia instanceof. Przydaje się tylko do szybkich hacków na źle zaprojektowanym kodzie. Jeśli nie lubisz OOP, napisz w innym języku (jest ich mnóstwo). Po prostu powiedz „nie” aplikacji instanceof!
Scott Biggs
5
@ScottBiggs Czy istnieje dobra alternatywa instanceofgdy nadrzędne equals?
Ben Aaronson,

Odpowiedzi:

228

instanceofsłowo kluczowe jest operatorem binarnym używanym do testowania, czy obiekt (instancja) jest podtypem danego Type.

Wyobrażać sobie:

interface Domestic {}
class Animal {}
class Dog extends Animal implements Domestic {}
class Cat extends Animal implements Domestic {}

Wyobraź sobie dog obiekt utworzony za pomocą Object dog = new Dog():

dog instanceof Domestic // true - Dog implements Domestic
dog instanceof Animal   // true - Dog extends Animal
dog instanceof Dog      // true - Dog is Dog
dog instanceof Object   // true - Object is the parent type of all objects

Jednakże, z Object animal = new Animal();,

animal instanceof Dog // false

ponieważ Animaljest nadtypem Dogi prawdopodobnie mniej „wyrafinowanym”.

I,

dog instanceof Cat // does not even compile!

Dzieje się tak, ponieważ Dognie jest on ani podtypem, ani nadtypem Cat, a także go nie implementuje.

Zauważ, że zmienna użyta dogpowyżej jest typu Object. Ma to na celu pokazanie, że instanceofjest to operacja w czasie wykonywania i prowadzi nas do przypadku użycia: aby reagować inaczej w zależności od typu obiektów w czasie wykonywania .

Uwaga: expressionThatIsNull instanceof Tjest fałszywa dla wszystkich typów T.

Miłego kodowania.

Cache Staheli
źródło
14
Właśnie próbowałem - Object dog = new Dog(); System.out.println(dog instanceof Cat);. Kompiluje się dobrze i drukuje false. Kompilator nie może określić w czasie kompilacji, który dognie może być Cat (zgodnie z regułami w JLS)
Erwin Bolwidt
@ErwinBolwidt Popełniłeś błąd, próbując tego. Dla każdego, kto się zastanawia: JLS Section 15.20.2 to ten, którego szukasz. Dla minimalnego niepracującego przykładu:boolean b = "foo" instanceof Integer;
Felix S
3
@FelixS Musisz ponownie przeczytać odpowiedź. Odpowiedź jest o Object indirect = ...; if (indirect instanceof Something). Nie chodzi o to, if (literal instanceof Something)jak wydajesz się zakładać.
Erwin Bolwidt
1
@ErwinBolwidt Och, racja, musiałem pominąć tę Object dogczęść. Mój błąd!
Felix S
dog instanceof Cat // does not even compile!(bo to jest klasa). Gdyby Catbył interfejs, to by się skompilował.
Hamza Belmellouki
44

Jest to operator, który zwraca prawdę, jeśli lewa strona wyrażenia jest instancją nazwy klasy po prawej stronie.

Pomyśl o tym w ten sposób. Powiedzmy, że wszystkie domy w twoim bloku zostały zbudowane z tych samych planów. Dziesięć domów (obiektów), jeden zestaw planów (definicja klasy).

instanceofto przydatne narzędzie, gdy masz kolekcję obiektów i nie jesteś pewien, czym one są. Załóżmy, że masz zbiór kontrolek w formularzu. Chcesz odczytać stan zaznaczenia wszystkich pól wyboru, ale nie możesz poprosić zwykłego starego obiektu o stan zaznaczenia. Zamiast tego zobaczysz, czy każdy obiekt jest polem wyboru, a jeśli tak, przerzuć go na pole wyboru i sprawdź jego właściwości.

if (obj instanceof Checkbox)
{
    Checkbox cb = (Checkbox)obj;
    boolean state = cb.getState();
}
Michael Petrotta
źródło
15
Oznacza to, że używanie instanceofmoże uczynić go bezpiecznym do przygnębienia.
Raedwald
29

Jak opisano na tej stronie :

instanceofOperator może być użyty do testu, jeśli obiekt jest typu określonego ...

if (objectReference instanceof type)

Szybki przykład:

String s = "Hello World!"
return s instanceof String;
//result --> true

Jednak zastosowanie instanceofdo zmiennej / wyrażenia odniesienia o wartości null zwraca wartość false.

String s = null;
return s instanceof String;
//result --> false

Ponieważ podklasa jest `` typem '' swojej nadklasy, możesz użyć instanceofdo sprawdzenia tego ...

class Parent {
    public Parent() {}
}

class Child extends Parent {
    public Child() {
        super();
    }
}

public class Main {
    public static void main(String[] args) {
        Child child = new Child();
        System.out.println( child instanceof Parent );
    }
}
//result --> true

Mam nadzieję, że to pomoże!

fireshadow52
źródło
15

Ten operator umożliwia określenie typu obiektu. Zwraca aboolean wartość.

Na przykład

package test;

import java.util.Date;
import java.util.Map;
import java.util.HashMap;

public class instanceoftest
{
    public static void main(String args[])
    {
        Map m=new HashMap();
        System.out.println("Returns a boolean value "+(m instanceof Map));
        System.out.println("Returns a boolean value "+(m instanceof HashMap));
        System.out.println("Returns a boolean value "+(m instanceof Object));
        System.out.println("Returns a boolean value "+(m instanceof Date));
    }
} 

wynik to:

Returns a boolean value true
Returns a boolean value true
Returns a boolean value true
Returns a boolean value false
Purendra Agrawal
źródło
14

Jeśli sourcejest objectzmienną, instanceofto sposób na sprawdzenie, czy jest to zmienna, Buttonczy nie.

Daniel A. White
źródło
5

Jak wspomniano w innych odpowiedziach, typowym kanonicznym zastosowaniem instanceofjest sprawdzenie, czy identyfikator odnosi się do bardziej konkretnego typu. Przykład:

Object someobject = ... some code which gets something that might be a button ...
if (someobject instanceof Button) {
    // then if someobject is in fact a button this block gets executed
} else {
    // otherwise execute this block
}

Zwróć jednak uwagę, że typ wyrażenia po lewej stronie musi być rodzicielem wyrażenia po prawej stronie (patrz JLS 15.20.2 i Java Puzzlers, # 50, str . 114 ). Na przykład następujące elementy nie zostaną skompilowane:

public class Test {
    public static void main(String [] args) {
        System.out.println(new Test() instanceof String); // will fail to compile
    }
}

Nie można skompilować się z komunikatem:

Test.java:6: error: inconvertible types
        System.out.println(t instanceof String);
                       ^
  required: String
  found:    Test
1 error

Jak Testnie jest klasą nadrzędną String. OTOH, to doskonale się kompiluje i drukuje falsezgodnie z oczekiwaniami:

public class Test {
    public static void main(String [] args) {
        Object t = new Test();
        // compiles fine since Object is a parent class to String
        System.out.println(t instanceof String); 
    }
}
Adam Parkin
źródło
Dzięki za link do specyfikacji!
jpaugh
1
public class Animal{ float age; }

public class Lion extends Animal { int claws;}

public class Jungle {
    public static void main(String args[]) {

        Animal animal = new Animal(); 
        Animal animal2 = new Lion(); 
        Lion lion = new Lion(); 
        Animal animal3 = new Animal(); 
        Lion lion2 = new Animal();   //won't compile (can't reference super class object with sub class reference variable) 

        if(animal instanceof Lion)  //false

        if(animal2 instanceof Lion)  //true

        if(lion insanceof Lion) //true

        if(animal3 instanceof Animal) //true 

    }
}
bangbang
źródło
1

Może być używany jako skrót przy sprawdzaniu równości.

Więc ten kod

if(ob != null && this.getClass() == ob.getClass) {
}

Można zapisać jako

if(ob instanceOf ClassA) {
}
mirmdasif
źródło
1

Większość ludzi poprawnie wyjaśniła „co” w tym pytaniu, ale nikt nie wyjaśnił poprawnie „jak”.

Oto prosta ilustracja:

String s = new String("Hello");
if (s instanceof String) System.out.println("s is instance of String"); // True
if (s instanceof Object) System.out.println("s is instance of Object"); // True
//if (s instanceof StringBuffer) System.out.println("s is instance of StringBuffer"); // Compile error
Object o = (Object)s;
if (o instanceof StringBuffer) System.out.println("o is instance of StringBuffer"); //No error, returns False
else System.out.println("Not an instance of StringBuffer"); // 
if (o instanceof String) System.out.println("o is instance of String"); //True

Wyjścia:

s is instance of String
s is instance of Object
Not an instance of StringBuffer
o is instance of String

Powód błędu kompilatora podczas porównywania sz StringBuffer jest dobrze wyjaśniony w dokumentacji :

Można go użyć do sprawdzenia, czy obiekt jest instancją klasy, instancją podklasy lub instancją klasy implementującej określony interfejs.

co oznacza, że ​​LHS musi być instancją RHS lub klasy, która albo implementuje RHS, albo rozszerza RHS.

Jak w takim razie korzystać z instanceof?
Ponieważ każda klasa rozszerza Object, rzutowanie typów LHS na obiekt zawsze będzie działać na twoją korzyść:

String s = new String("Hello");
if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //No compiler error now :)
else System.out.println("Not an instance of StringBuffer");

Wyjścia:

Not an instance of StringBuffer
sziraqui
źródło
Dlaczego w ostatnim przykładzie zwraca „To nie jest instancja StringBuffer”? Odkąd wpisałeś s do Object na LHS i sprawdziłeś, czy jest to instancja RHS if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //shouldn't this be true, skoro tworzymy s do Object?
sofs 1
Ponieważ s jest odniesieniem do obiektu String (Java wykorzystuje dynamiczny polimorfizm w przeciwieństwie do C ++), a String nie jest podklasą klasy StringBuffer.
sziraqui
0

Wystąpienie słowa kluczowego jest pomocne, gdy chcesz poznać instancję konkretnego obiektu.

Załóżmy, że rzucasz wyjątek, a gdy masz catch, wykonaj sumaryczną operację niestandardową, a następnie ponownie kontynuuj zgodnie z logiką (rzuty lub dziennik itp.)

Przykład: 1) Utworzony przez użytkownika wyjątek niestandardowy „InvalidExtensionsException” i zgłoś go zgodnie z logiką

2) Teraz w catch block catch (Exception e) {wykonaj logikę sumy, jeśli typ wyjątku to „InvalidExtensionsException”

InvalidExtensionsException InvalidException =(InvalidExtensionsException)e;

3) Jeśli nie sprawdzasz wystąpienia i typem wyjątku jest wyjątek wskaźnika Null, kod nie działa.

Więc twoja logika powinna znajdować się wewnątrz instancji if (e instanceof InvalidExtensionsException) {InvalidExtensionsException InvalidException = (InvalidExtensionsException) e; }

Powyższy przykład to zła praktyka kodowania Jednak ten przykład pomoże ci zrozumieć użycie jego wystąpienia.

vaquar khan
źródło
0

Najlepsze wyjaśnienie to jls . Zawsze staraj się sprawdzić, co mówi źródło. Tam uzyskasz najlepszą odpowiedź i wiele więcej. Powielanie niektórych części tutaj:

Typ operandu RelationalExpression operatora instanceof musi być typem referencyjnym lub typem null; w przeciwnym razie wystąpi błąd w czasie kompilacji.

Jest to błąd czasu kompilacji, jeśli typ odniesienia wymieniony po operatorze instanceof nie oznacza typu odwołania, który można reififable (§ 4.7).

Jeśli rzutowanie (§15.16) wyrażenia RelationalExpression na typ odniesienia zostałoby odrzucone jako błąd w czasie kompilacji, to wystąpienie wyrażenia relacyjnego podobnie generuje błąd w czasie kompilacji. W takiej sytuacji wynik wystąpienia wyrażenia nigdy nie mógłby być prawdziwy.

nanosoft
źródło
0

Plik java instanceofOperator służy do testowania, czy obiekt jest instancją określonego typu (klasa, podklasa lub interfejs).

Instancja w Javie jest również nazywana typem, comparison operatorponieważ porównuje instancję z typem. Zwraca albo truelub false. Jeśli zastosujemy instanceofoperator do dowolnej zmiennej, która ma nullwartość, zwracafalse .

Z JDK 14+, który zawiera JEP 305 , możemy również wykonać „Pattern Matching” dlainstanceof

Wzorce zasadniczo sprawdzają, czy wartość ma określony typ, i mogą wyodrębniać informacje z wartości, gdy ma ona pasujący typ. Dopasowanie wzorców pozwala na bardziej przejrzyste i wydajniejsze wyrażenie wspólnej logiki w systemie, a mianowicie warunkowe usuwanie komponentów z obiektów.

Przed wersją Java 14

if (obj instanceof String) {
    String str = (String) obj; // need to declare and cast again the object
    .. str.contains(..) ..
}else{
     str = ....
}

Ulepszenia Java 14

if (!(obj instanceof String str)) {
    .. str.contains(..) .. // no need to declare str object again with casting
} else {
    .. str....
}

Możemy również łączyć ze sobą kontrolę typu i inne warunki

if (obj instanceof String str && str.length() > 4) {.. str.contains(..) ..}

Użycie dopasowania wzorców w programie instanceofpowinno zmniejszyć całkowitą liczbę rzutów jawnych w programach Java.

PS : instanceOfbędzie pasować tylko wtedy, gdy obiekt nie jest pusty, wtedy tylko można go przypisać str.

Bhanu Hoysala
źródło
-1
class Test48{
public static void main (String args[]){
Object Obj=new Hello();
//Hello obj=new Hello;
System.out.println(Obj instanceof String);
System.out.println(Obj instanceof Hello);
System.out.println(Obj instanceof Object);
Hello h=null;
System.out.println(h instanceof Hello);
System.out.println(h instanceof Object);
}
}  
sajid sadiq
źródło
1
Nie wysyłaj tylko odpowiedzi na kod w StackOverflow. Proszę śmiało i dodaj wyjaśnienie.
L. Guthardt,
-2

Bardzo prosty przykład kodu:

If (object1 instanceof Class1) {
   // do something
} else if (object1 instanceof Class2) {
   // do something different
}

Uważaj tutaj. W powyższym przykładzie, jeśli Class1 to Object, pierwsze porównanie zawsze będzie prawdziwe. Tak więc, podobnie jak w przypadku wyjątków, liczy się hierarchia!

mjuarez
źródło
-2

Możesz użyć Map, aby uzyskać wyższą abstrakcję na wystąpieniu

private final Map<Class, Consumer<String>> actions = new HashMap<>();

Następnie mając taką mapę dodaj do niej jakąś akcję:

actions.put(String.class, new Consumer<String>() {
        @Override
        public void accept(String s) {
           System.out.println("action for String");       
        }
    };

Następnie mając obiekt nieznanego typu, możesz uzyskać określone działanie z tej mapy:

actions.get(someObject).accept(someObject)
tomekl007
źródło
-2

Operator instanceof służy do sprawdzania, czy obiekt jest instancją określonego typu. (klasa, podklasa lub interfejs).

Instancja instanceof jest również znana jako operator porównania typów, ponieważ porównuje instancję z typem. Zwraca prawdę lub fałsz.

class Simple1 {  
public static void main(String args[]) {  
Simple1 s=new Simple1();  
System.out.println(s instanceof Simple1); //true  
}  
}  

Jeśli zastosujemy operator instanceof z dowolną zmienną, która ma wartość null, zwraca false.

Viraj Pai
źródło