ตัวดำเนินการ 'instanceof' ที่ใช้ใน Java คืออะไร


163

สิ่งที่เป็นinstanceofผู้ประกอบการใช้? ฉันเคยเห็นสิ่งที่ชอบ

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

แต่มันก็ไม่สมเหตุสมผลสำหรับฉัน ฉันทำวิจัยแล้ว แต่มีตัวอย่างมาโดยไม่มีคำอธิบายใด ๆ


38
ไม่มีอะไรผิดปกติกับการถามคำถามที่นี่ แต่ถ้าคุณเรียนรู้ Java คุณอาจต้องการรับหนังสือ หนังสือ Java ที่เหมาะสมจะมีคำตอบสำหรับคำถามนี้และอีก 1,000 เล่มที่คุณจะได้รับ
ประธานาธิบดี James K. Polk

ผู้ประกอบการดังกล่าวมีการใช้งานเฉพาะหลายอย่าง นี่จะเป็นคำถามที่เฉพาะเจาะจงหากมีการขอคำอธิบายของหนึ่งในตัวอย่างที่ไม่สมเหตุสมผลสำหรับคุณ
Raedwald

2
คำตอบด้านล่างถูกต้องอย่างไรก็ตามโปรดทราบว่า instanceof เป็นตัวดำเนินการที่ใช้งานมากเกินไป 9 ครั้งจาก 10 มันสามารถถูกแทนที่ด้วยการใช้ polymorphism ที่เหมาะสม (ไม่เสมอไป แต่บ่อยครั้ง)
Richard Tingle

ฉันจะไปไกลกว่า Richard: ฉันไม่เคยเห็นการใช้งาน instanceof ที่ถูกต้อง มันมีประโยชน์สำหรับการแฮ็กอย่างรวดเร็วบนโค้ดที่ออกแบบไม่ดีเท่านั้น หากคุณไม่ชอบ OOP ให้เขียนเป็นภาษาอื่น (มีมากมาย) เพียงแค่พูดว่า "ไม่" กับอินสแตนซ์ของ!
Scott Biggs

5
@ScottBiggs มีทางเลือกที่ดีinstanceofเมื่อเอาชนะequals?
Ben Aaronson

คำตอบ:


228

instanceofkeyword เป็นตัวดำเนินการไบนารีที่ใช้ในการทดสอบว่าวัตถุ (อินสแตนซ์) เป็นประเภทย่อยของประเภทที่กำหนด

Imagine:

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ไม่ใช่ประเภทย่อยหรือ supertype ของCatและมันก็ไม่ได้ใช้มัน

โปรดทราบว่าตัวแปรที่ใช้สำหรับการดังกล่าวข้างต้นเป็นประเภทdog Objectนี้คือการแสดงinstanceofเป็นรันไทม์การดำเนินงานและนำเราไปสู่การ / กรณีใช้: การตอบสนองตามที่แตกต่างกันเมื่อวัตถุประเภทที่รันไทม์

สิ่งที่ควรทราบ: เป็นเท็จชนิดทั้งหมดexpressionThatIsNull instanceof TT

การเข้ารหัสที่มีความสุข


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;
Felix S

3
@ FelixS คุณต้องอ่านคำตอบอีกครั้ง Object indirect = ...; if (indirect instanceof Something)คำตอบที่เป็นเรื่องเกี่ยวกับ มันไม่เกี่ยวกับif (literal instanceof Something)อย่างที่คุณคิด
Erwin Bolwidt

1
@ErwinBolwidt โอ้ใช่ฉันต้องข้ามObject dogส่วนนี้ไปแล้ว ความผิดฉันเอง!
เฟลิกซ์ S

dog instanceof Cat // does not even compile!(เพราะเป็นคลาส) หากCatเป็นอินเทอร์เฟซก็จะรวบรวม
Hamza Belmellouki

44

มันเป็นโอเปอเรเตอร์ที่คืนค่าจริงถ้าด้านซ้ายของนิพจน์เป็นตัวอย่างของชื่อคลาสทางด้านขวา

คิดแบบนี้ สมมติว่าบ้านทั้งหมดในบล็อกของคุณถูกสร้างขึ้นจากพิมพ์เขียวเดียวกัน บ้านสิบหลัง (วัตถุ), พิมพ์เขียวหนึ่งชุด (คำจำกัดความของชั้นเรียน)

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กับตัวแปร / นิพจน์อ้างอิงเป็น null จะส่งคืนค่าเท็จ

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

โอเปอเรเตอร์นี้อนุญาตให้คุณกำหนดประเภทของวัตถุ มันคืน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


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 StringOTOH นี้รวบรวมได้อย่างสมบูรณ์และพิมพ์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

วิธีการใช้งานใช้งานอินสแตนซ์แล้ว?
เนื่องจากคลาสทุกคลาสจะขยายอ็อบเจกต์ 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" เมื่อคุณพิมพ์ไปที่ Object บน LHS และตรวจสอบว่ามันเป็นอินสแตนซ์ของ RHS หรือ if ((Object)s instanceof StringBuffer) System.out.println("Instance of StringBuffer"); //shouldn't this be trueไม่เนื่องจากเราพิมพ์ตัวอักษรเป็น Object
sofs1

เนื่องจาก s เป็นการอ้างอิงถึงวัตถุ String (Java ใช้ polymorphism แบบไดนามิกซึ่งแตกต่างจาก C ++) และ String ไม่ใช่ subclass ของ StringBuffer
sziraqui

0

ตัวดำเนินการ instanceof เปรียบเทียบวัตถุกับชนิดที่ระบุ คุณสามารถใช้มันเพื่อทดสอบว่าวัตถุเป็นอินสแตนซ์ของคลาสอินสแตนซ์ของคลาสย่อยหรืออินสแตนซ์ของคลาสที่ใช้อินเทอร์เฟซเฉพาะ

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


0

อินสแตนซ์ของคำหลักมีประโยชน์เมื่อคุณต้องการทราบอินสแตนซ์ของวัตถุเฉพาะ

สมมติว่าคุณกำลังโยนข้อยกเว้นและเมื่อคุณได้จับแล้วทำการดำเนินการที่กำหนดเองผลรวมแล้วดำเนินการต่อตามตรรกะของคุณอีกครั้ง (โยนหรือบันทึก ฯลฯ )

ตัวอย่าง: 1) ผู้ใช้สร้างข้อยกเว้นที่กำหนดเอง "InvalidExtensionsException" และโยนตามตรรกะ

2) ตอนนี้อยู่ใน catch catch catch (Exception e) {ใช้ตรรกะผลรวมหากประเภทการยกเว้นเป็น "InvalidExtensionsException"

InvalidExtensionsException InvalidException =(InvalidExtensionsException)e;

3) หากคุณไม่ได้ตรวจสอบอินสแตนซ์ของและประเภทการยกเว้นเป็นตัวชี้ Null ยกเว้นรหัสของคุณจะแตก

ดังนั้นตรรกะของคุณควรอยู่ในอินสแตนซ์ของ if (e instanceof InvalidExtensionsException) {InvalidExtensionsException InvalidException = (InvalidExtensionsException) e; }

ตัวอย่างข้างต้นคือการฝึกเขียนโค้ดที่ผิดอย่างไรก็ตามตัวอย่างนี้ช่วยให้คุณเข้าใจการใช้งานอินสแตนซ์ของมัน


0

คำอธิบายที่ดีที่สุดคือJLS พยายามตรวจสอบแหล่งที่มาพูดเสมอ แล้วคุณจะได้รับคำตอบที่ดีที่สุดบวกกับอีกมากมาย ผลิตซ้ำบางส่วนที่นี่:

ชนิดของตัวถูกดำเนินการ Relational Expression ของตัวดำเนินการ instanceof ต้องเป็นชนิดการอ้างอิงหรือชนิด null มิฉะนั้นจะเกิดข้อผิดพลาดในการคอมไพล์เวลา

มันเป็นข้อผิดพลาดในการคอมไพล์เวลาถ้า ReferenceType ที่กล่าวถึงหลังจากตัวดำเนินการ instanceof ไม่แสดงประเภทการอ้างอิงที่สามารถใช้ซ้ำได้ (§4.7)

หากการร่าย (§15.16) ของ Relational Expression ไปยัง ReferenceType จะถูกปฏิเสธว่าเป็นข้อผิดพลาดในการคอมไพล์เวลาดังนั้นอินสแตนซ์ของนิพจน์เชิงสัมพันธ์จะสร้างข้อผิดพลาดในการคอมไพล์ในเวลาเดียวกัน ในสถานการณ์เช่นนี้ผลลัพธ์ของการแสดงออกของอินสแตนซ์ไม่อาจเป็นจริง


0

ตัวinstanceofดำเนินการjava ถูกใช้เพื่อทดสอบว่าวัตถุเป็นอินสแตนซ์ของชนิดที่ระบุ (คลาสหรือคลาสย่อยหรืออินเทอร์เฟซ)

อินสแตนซ์ของ java เป็นที่รู้จักกันว่าเป็นประเภทcomparison operatorเพราะมันเปรียบเทียบอินสแตนซ์ที่มีประเภท ก็จะส่งกลับอย่างใดอย่างหนึ่งหรือtrue falseถ้าเราใช้instanceofผู้ประกอบการที่มีตัวแปรใด ๆ ที่มีค่าก็จะส่งกลับnullfalse

จาก 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 โปรดไปข้างหน้าและเพิ่มคำอธิบาย
L. Guthardt

-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 ถูกใช้เพื่อตรวจสอบว่าวัตถุเป็นอินสแตนซ์ของชนิดที่ระบุ (คลาสหรือคลาสย่อยหรืออินเตอร์เฟส)

อินสแตนซ์ของมันยังเป็นที่รู้จักกันในนามผู้ดำเนินการเปรียบเทียบประเภทเพราะมันเปรียบเทียบอินสแตนซ์ที่มีประเภท มันจะส่งกลับทั้งจริงหรือเท็จ

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

ถ้าเราใช้ตัวดำเนินการ instanceof กับตัวแปรใด ๆ ที่มีค่า Null มันจะคืนค่าเท็จ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.