Для чего используется оператор instanceof в Java?

163

Для чего используется instanceofоператор? Я видел такие вещи, как

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

Но все это не имело смысла для меня. Я провел свое исследование, но придумал только примеры без каких-либо объяснений.

Бен
источник
38
Здесь нет ничего плохого в том, чтобы задавать вопросы, но если вы изучаете Java, вы можете получить книгу. Любая приличная книга по Java будет иметь ответ на этот вопрос и следующие 1000, которые вы получите.
Президент Джеймс К. Полк
Такой оператор имеет много конкретных применений. Это был бы конкретный вопрос, если бы он попросил объяснить один из примеров, который не имеет смысла для вас.
Raedwald
2
Приведенные ниже ответы верны, однако обратите внимание, что instanceof - это чрезмерно используемый оператор 9 раз из 10, его можно заменить правильным использованием полиморфизма (не всегда, но часто)
Ричард Тингл
Я пошел бы дальше, чем Ричард: я НИКОГДА не видел действительного использования instanceof. Это полезно только для быстрого взлома поверх плохо спроектированного кода. Если вам не нравится ООП, пишите на другом языке (их много). Просто скажите «нет» instanceof!
Скотт Биггс
5
@ScottBiggs Есть ли хорошая альтернатива instanceofпереопределению equals?
Бен Ааронсон

Ответы:

228

instanceofКлючевое слово - это двоичный оператор, используемый для проверки, является ли объект (экземпляр) подтипом данного Типа.

Представить:

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

Представьте себе dog объект , созданный с помощью 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

Тем не менее, с Object animal = new Animal();,

animal instanceof Dog // false

потому что Animalэто супертип Dogи, возможно, менее "изысканный".

И,

dog instanceof Cat // does not even compile!

Это потому, что не Dogявляется ни подтипом, ни супертипом Cat, и он также не реализует его.

Обратите внимание, что переменная, используемая для dogвыше, имеет тип Object. Это показывает, instanceofчто это операция во время выполнения и приводит нас к варианту использования: реагировать по-разному в зависимости от типа объекта во время выполнения .

На что обратить внимание: expressionThatIsNull instanceof Tложно для всех типов T.

Удачного кодирования.

Кеш стахели
источник
14
Я только что попробовал Object dog = new Dog(); System.out.println(dog instanceof Cat);. Это прекрасно компилирует и печатает false. Компилятору не разрешается определять во время компиляции, что dogне может быть Cat (согласно правилам в JLS)
Erwin Bolwidt
@ErwinBolwidt Вы сделали ошибку, когда попробовали это. Для тех, кто интересуется: JLS Раздел 15.20.2 - это то, что вы ищете. Для минимального нерабочего примера:boolean b = "foo" instanceof Integer;
Феликс С
3
@FelixS Вам нужно прочитать ответ снова. Ответ о Object indirect = ...; if (indirect instanceof Something). Дело не в том, if (literal instanceof Something)что вы, похоже, предполагаете.
Эрвин Болвидт
1
@ErwinBolwidt Да, конечно, я пропустил Object dogчасть. Виноват!
Феликс С
dog instanceof Cat // does not even compile!(потому что это класс). Если бы Catбыл интерфейс, то он был бы скомпилирован.
Хамза Белмеллуки
44

Это оператор, который возвращает true, если левая часть выражения является экземпляром имени класса с правой стороны.

Подумайте об этом таким образом. Скажем, все дома в вашем квартале были построены из одинаковых чертежей. Десять домов (объектов), один набор чертежей (определение класса).

instanceofэто полезный инструмент, когда у вас есть коллекция объектов, и вы не уверены, что они есть. Допустим, у вас есть коллекция элементов управления в форме. Вы хотите прочитать проверенное состояние всех имеющихся флажков, но вы не можете запросить простой старый объект для его проверенного состояния. Вместо этого вы увидите, является ли каждый объект флажком, и если он есть, приведите его к флажку и проверьте его свойства.

if (obj instanceof Checkbox)
{
    Checkbox cb = (Checkbox)obj;
    boolean state = cb.getState();
}
Майкл Петротта
источник
15
То есть использование instanceofможет сделать его безопасным для подавления.
Raedwald
29

Как описано на этом сайте :

instanceofОператор может быть использован для тестирования является ли объект типа конкретного ...

if (objectReference instanceof type)

Быстрый пример:

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

Однако применение instanceofк пустой переменной / выражению ссылки возвращает false.

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

Поскольку подкласс является «типом» своего суперкласса, вы можете использовать это instanceofдля проверки ...

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

Надеюсь, это поможет!

fireshadow52
источник
15

Этот оператор позволяет определить тип объекта. Возвращает booleanзначение.

Например

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

выход:

Returns a boolean value true
Returns a boolean value true
Returns a boolean value true
Returns a boolean value false
Пурендра Агравал
источник
14

Если sourceэто objectпеременная, instanceofэто способ проверить, является ли она Buttonили нет.

Даниэль А. Уайт
источник
5

Как упоминалось в других ответах, каноническое типичное использование instanceofдля проверки, относится ли идентификатор к более конкретному типу. Пример:

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
}

Однако обратите внимание, что тип левого выражения должен быть родительским типом правого выражения (см. JLS 15.20.2 и Java Puzzlers, # 50, pp114 ). Например, следующее не удастся скомпилировать:

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

Это не в состоянии скомпилировать с сообщением:

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

Как Testне родительский класс String. OTOH, это прекрасно компилируется и печатается, falseкак и ожидалось:

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); 
    }
}
Адам Паркин
источник
Спасибо за ссылку на спецификацию!
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 

    }
}
ПИФ-паф
источник
1

Может использоваться как сокращение в проверке равенства.

Итак, этот код

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

Может быть написано как

if(ob instanceOf ClassA) {
}
mirmdasif
источник
1

Большинство людей правильно объяснили «Что» в этом вопросе, но никто не объяснил «Как» правильно.

Итак, вот простая иллюстрация:

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

Выходы:

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

Причина ошибки компилятора при сравнении sсо StringBuffer хорошо объяснена в документации :

Вы можете использовать его, чтобы проверить, является ли объект экземпляром класса, экземпляром подкласса или экземпляром класса, который реализует определенный интерфейс.

что подразумевает, что LHS должен быть либо экземпляром RHS, либо класса, который либо реализует RHS, либо расширяет RHS.

Как использовать использовать instanceof тогда?
Поскольку каждый класс расширяет объект, приведение типов LHS к объекту всегда будет работать в вашу пользу:

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

Выходы:

Not an instance of StringBuffer
sziraqui
источник
В последнем примере, почему он возвращает «Не экземпляр StringBuffer»? Так как вы типизировали s для Object на LHS и проверили, является ли он экземпляром RHS if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //shouldn't this be true, так как мы типизируем s для Object?
sofs1
Поскольку s является ссылкой на объект String (Java использует динамический полиморфизм в отличие от C ++), а String не является подклассом StringBuffer.
Сираки
0

Оператор instanceof сравнивает объект с указанным типом. Вы можете использовать его, чтобы проверить, является ли объект экземпляром класса, экземпляром подкласса или экземпляром класса, который реализует определенный интерфейс.

http://download.oracle.com/javase/tutorial/java/nutsandbolts/op2.html

Бенджамин Удинк тен Кейт
источник
0

Экземпляр ключевого слова полезен, когда вы хотите узнать экземпляр конкретного объекта.

Предположим, что вы выбросили исключение, и когда у вас есть catch, затем выполните пользовательскую операцию sum, а затем снова продолжите согласно вашей логике (throws или log и т. Д.)

Пример: 1) Пользователь создал пользовательское исключение «InvalidExtensionsException» и выбросил его согласно логике

2) Теперь в блоке catch catch (Exception e) {выполнить логику суммы, если тип исключения "InvalidExtensionsException"

InvalidExtensionsException InvalidException =(InvalidExtensionsException)e;

3) Если вы не проверяете экземпляр, а типом исключения является исключение нулевого указателя, ваш код сломается.

Таким образом, ваша логика должна быть внутри экземпляра if (e instanceof InvalidExtensionsException) {InvalidExtensionsException InvalidException = (InvalidExtensionsException) e; }

Вышеприведенный пример - неправильная практика кодирования. Однако этот пример поможет вам понять использование его экземпляра.

Ваквар хан
источник
0

Лучшее объяснение - JLS . Всегда пытайтесь проверить, что говорит источник. Там вы получите лучший ответ и многое другое. Воспроизведение некоторых частей здесь:

Тип операнда RelationalExpression оператора instanceof должен быть ссылочным типом или нулевым типом; в противном случае возникает ошибка времени компиляции.

Это ошибка времени компиляции, если ReferenceType, упомянутый после оператора instanceof, не обозначает ссылочный тип, который можно переопределять (§4.7).

Если приведение (§15.16) выражения RelationalExpression к ReferenceType будет отклонено как ошибка времени компиляции, то реляционное выражение instanceof аналогичным образом выдает ошибку времени компиляции. В такой ситуации результат выражения instanceof никогда не может быть истинным.

Nanosoft
источник
0

Оператор java instanceofиспользуется для проверки того, является ли объект экземпляром указанного типа (класс, подкласс или интерфейс).

Instanceof в java также известен как тип, comparison operatorпоскольку он сравнивает экземпляр с типом. Возвращает либо trueили false. Если мы применяем instanceofоператор с любой переменной, которая имеет nullзначение, он возвращает false.

Из JDK 14+, который включает в себя JEP 305, мы также можем выполнить «Сопоставление с образцом» дляinstanceof

Шаблоны в основном проверяют, что значение имеет определенный тип, и могут извлекать информацию из значения, когда оно имеет соответствующий тип. Сопоставление с образцом позволяет более четко и эффективно выражать общую логику в системе, а именно условное удаление компонентов из объектов.

До Java 14

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

Улучшения Java 14

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

Мы также можем объединить проверку типа и другие условия вместе

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

Использование сопоставления с образцом в instanceofдолжно уменьшить общее число явных приведений в программах Java.

PS : instanceOfбудет соответствовать только тогда, когда объект не нулевой, тогда только ему можно присвоить str.

Бхану Хойсала
источник
-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);
}
}  
Саджид Садик
источник
1
Не размещайте ответы только в коде StackOverflow. Пожалуйста, продолжайте и добавьте объяснение.
Л. Гутардт
-2

Очень простой пример кода:

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

Будьте осторожны здесь. В приведенном выше примере, если Class1 - Object, первое сравнение всегда будет истинным. Так что, как и с исключениями, иерархический порядок имеет значение!

mjuarez
источник
-2

Вы можете использовать карту, чтобы сделать более высокую абстракцию в случае

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

Затем, имея такую ​​карту, добавьте к ней некоторые действия:

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

Затем, имея Объект неизвестного типа, вы можете получить конкретное действие с этой карты:

actions.get(someObject).accept(someObject)
tomekl007
источник
-2

Оператор instanceof используется для проверки того, является ли объект экземпляром указанного типа. (класс или подкласс или интерфейс).

Instanceof также известен как оператор сравнения типов, потому что он сравнивает экземпляр с типом. Возвращает либо true, либо false.

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

Если мы применяем оператор instanceof к любой переменной, которая имеет нулевое значение, она возвращает false.

Вирадж Пай
источник