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


163

Для чого instanceofвикористовується оператор? Я бачив подібні речі

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

Але нічого з цього не мало для мене сенсу. Я провів своє дослідження, але придумав лише приклади без будь-яких пояснень.


38
Тут немає нічого поганого в тому, щоб задавати питання, але якщо ви вивчаєте Java, ви можете отримати книгу. Будь-яка гідна книга на Java отримала б відповідь на це питання і наступні 1000, які ви збираєтеся мати.
президент Джеймс К. Полк

Такий оператор має багато специфічних застосувань. Це було б конкретним питанням, якби він попросив пояснення одного із прикладів, які не мали для вас сенсу.
Raedwald

2
Відповіді, наведені нижче, є правильними, проте зауважте, що instanceof є оператором, який перевтомлюється в 9 разів з 10, його можна замінити правильним використанням поліморфізму (не завжди, але часто)
Річард Тінгл

Я б пішов далі, ніж Річард: Я НІКОЛИ не бачив дійсного використання instanceof. Це корисно лише для швидких злому поверх погано розробленого коду. Якщо вам не подобається OOP, пишіть іншою мовою (їх є багато). Просто скажіть, "ні" для 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не може бути Кішкою (згідно з правилами JLS)
Ервін Болвідт

@ErwinBolwidt Ви помилилися, коли спробували це. Для всіх, хто цікавиться: JLS Розділ 15.20.2 - це той, який ви шукаєте. Для мінімального неробочого прикладу:boolean b = "foo" instanceof Integer;
Felix S

3
@FelixS Вам потрібно ще раз прочитати відповідь. Відповідь о Object indirect = ...; if (indirect instanceof Something). Справа не в тому, if (literal instanceof Something)як ти, здається, припускаєш.
Ервін Болвідт

1
@ErwinBolwidt О, так, я, мабуть, пропустив Object dogчастину. Моє ліжко!
Felix S

dog instanceof Cat // does not even compile!(бо це клас). Якби Catбув інтерфейс, то він би компілювався.
Hamza Belmellouki

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нульову довідкову змінну / вираз, повертається хибним.

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

Я сподіваюся, що це допомагає!


15

Цей оператор дозволяє визначити тип об'єкта. Він повертає aboolean значення.

Наприклад

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


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

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.

Як використовувати use 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

В останньому прикладі, чому він повертає "Не екземпляр 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.
sziraqui

0

Оператор instanceof порівнює об'єкт із заданим типом. Ви можете використовувати його для перевірки, чи об'єкт є екземпляром класу, екземпляром підкласу або екземпляром класу, який реалізує певний інтерфейс.

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


0

Екземпляр ключового слова корисний, коли ви хочете знати екземпляр конкретного об'єкта.

Припустимо, ви викидаєте виняток, і коли у вас є спіймання, виконайте спеціальну операцію за сумою, а потім знову продовжуйте згідно з вашою логікою (кидки або журнал тощо)

Приклад: 1) Користувач створив спеціальний виняток "InvalidExtensionsException" і кине його відповідно до логіки

2) Тепер у лові блоку вилову (Виняток е) {виконувати логіку суми, якщо тип винятку "InvalidExtensionsException"

InvalidExtensionsException InvalidException =(InvalidExtensionsException)e;

3) Якщо ви не перевіряєте екземпляр і тип винятку - Null pointer виключення, ваш код порушиться.

Отже, ваша логіка повинна знаходитись, наприклад, у випадку if (e instanceof InvalidExtensionsException) {InvalidExtensionsException InvalidException = (InvalidExtensionsException) e; }

Вищенаведений приклад - неправильна практика кодування, однак цей приклад допоможе вам зрозуміти використання його примірника.


0

Найкраще пояснення - jls . Завжди намагайтеся перевірити, що говорить джерело. Там ви отримаєте найкращу відповідь плюс набагато більше. Відтворення деяких деталей тут:

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

Це помилка часу компіляції, якщо ReferenceType, згаданий після оператора instance, не позначає тип посилання, який можна повторно піддавати (§4.7).

Якщо викид (§ 15.16) RelationalExpression до ReferenceType буде відхилений як помилка часу компіляції, то екземпляр реляційного вираження також видає помилку часу компіляції. У такій ситуації результат виразника вираження ніколи не може бути правдивим.


0

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

Examof в 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, перше порівняння завжди буде істинним. Отже, як і за винятками, ієрархічний порядок має значення!


-2

Ви можете використовувати Map, щоб зробити більш високу абстракцію екземпляра

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)

-2

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

Examof також відомий як оператор порівняння типів, оскільки порівнює екземпляр з типом. Він повертає істинне або хибне.

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

Якщо ми застосуємо оператор instanceof до будь-якої змінної, яка має нульове значення, вона поверне false.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.