Java อินสแตนซ์ของ Operator

1. บทนำ

ในบทช่วยสอนฉบับย่อนี้เราจะเรียนรู้เกี่ยวกับอินสแตนซ์ของตัวดำเนินการใน Java

2. อินสแตนซ์ของตัวดำเนินการคืออะไร?

instanceof เป็นตัวดำเนินการไบนารีที่ใช้ในการทดสอบว่าวัตถุเป็นประเภทที่กำหนดหรือไม่ ผลการดำเนินงานที่เป็นทั้งความจริงหรือเท็จ เป็นที่รู้จักกันว่าตัวดำเนินการเปรียบเทียบประเภทเนื่องจากเปรียบเทียบอินสแตนซ์กับประเภท

ก่อนที่จะส่งวัตถุที่ไม่รู้จักควรใช้อินสแตนซ์ของการตรวจสอบเสมอ การทำเช่นนี้ช่วยในการหลีกเลี่ยงClassCastExceptionในขณะรันไทม์

instanceofไวยากรณ์พื้นฐานของผู้ประกอบการคือ

(object) instanceof (type)

มาดูตัวอย่างพื้นฐานสำหรับตัวดำเนินการอินสแตนซ์ ก่อนอื่นมาสร้างคลาสรอบ :

public class Round { // implementation details }

ต่อไปมาสร้างคลาสRingที่ขยายRound :

public class Ring extends Round { // implementation details }

เราสามารถใช้instanceofเพื่อตรวจสอบว่าอินสแตนซ์ของRingเป็นประเภทRound หรือไม่ :

@Test public void givenWhenInstanceIsCorrect_thenReturnTrue() { Ring ring = new Ring(); Assert.assertTrue(ring instanceof Round); }

3. อินสแตนซ์ของ Operator ทำงานอย่างไร?

instanceofประกอบการทำงานบนหลักการของการเป็น-ความสัมพันธ์ แนวคิดของความสัมพันธ์ is-a ขึ้นอยู่กับการสืบทอดคลาสหรือการใช้งานอินเทอร์เฟซ

เพื่อสาธิตสิ่งนี้ให้สร้างอินเทอร์เฟซShape :

public interface Shape { // implementation details }

มาสร้างคลาสCircleที่ใช้อินเทอร์เฟซShapeและขยายคลาสRound :

public class Circle extends Round implements Shape { // implementation details }

instanceofผลจะเป็นจริงถ้าวัตถุเป็นตัวอย่างของประเภท:

@Test public void givenWhenObjectIsInstanceOfType_thenReturnTrue() { Circle circle = new Circle(); Assert.assertTrue(circle instanceof Circle); }

นอกจากนี้ยังจะเป็นจริงหากวัตถุนั้นเป็นตัวอย่างของคลาสย่อยของประเภท:

@Test public void giveWhenInstanceIsOfSubtype_thenReturnTrue() { Circle circle = new Circle(); Assert.assertTrue(circle instanceof Round); }

หากประเภทเป็นอินเทอร์เฟซจะคืนค่าจริงหากอ็อบเจ็กต์ใช้อินเทอร์เฟซ:

@Test public void givenWhenTypeIsInterface_thenReturnTrue() { Circle circle = new Circle(); Assert.assertTrue(circle instanceof Shape); }

ไม่สามารถใช้ตัวดำเนินการinstanceofได้หากไม่มีความสัมพันธ์ระหว่างออบเจ็กต์ที่กำลังเปรียบเทียบกับประเภทที่กำลังเปรียบเทียบด้วย

มาสร้างคลาสใหม่Triangleที่ใช้Shapeแต่ไม่มีความสัมพันธ์กับCircle :

public class Triangle implements Shape { // implementation details }

ตอนนี้ถ้าเราใช้instanceofเพื่อตรวจสอบว่าCircleเป็นอินสแตนซ์ของTriangle หรือไม่ :

@Test public void givenWhenComparingClassInDiffHierarchy_thenCompilationError() { Circle circle = new Circle(); Assert.assertFalse(circle instanceof Triangle); }

เราจะได้รับข้อผิดพลาดในการคอมไพล์เนื่องจากไม่มีความสัมพันธ์ระหว่างคลาสCircleและTriangle :

java.lang.Error: Unresolved compilation problem: Incompatible conditional operand types Circle and Triangle

4. ใช้instanceofกับObject Type

ใน Java ทุกคลาสจะสืบทอดมาจากคลาสObjectโดยปริยาย ดังนั้นการใช้อินสแตนซ์ของตัวดำเนินการกับประเภทวัตถุจะประเมินเป็นจริงเสมอ:

@Test public void givenWhenTypeIsOfObjectType_thenReturnTrue() { Thread thread = new Thread(); Assert.assertTrue(thread instanceof Object); }

5. การใช้อินสแตนซ์ของตัวดำเนินการเมื่อวัตถุเป็นโมฆะ

ถ้าเราใช้instanceofผู้ประกอบการเกี่ยวกับวัตถุใด ๆ ที่เป็นโมฆะก็จะส่งกลับเท็จ นอกจากนี้ไม่จำเป็นต้องตรวจสอบค่าว่างเมื่อใช้ตัวดำเนินการinstanceof

@Test public void givenWhenInstanceValueIsNull_thenReturnFalse() { Circle circle = null; Assert.assertFalse(circle instanceof Round); }

6. อินสแตนซ์ของและ Generics

การทดสอบและแคสต์อินสแตนซ์ขึ้นอยู่กับการตรวจสอบข้อมูลประเภทที่รันไทม์ ดังนั้นเราจึงไม่สามารถใช้instanceofร่วมกับประเภททั่วไปที่ถูกลบได้

ตัวอย่างเช่นหากเราพยายามรวบรวมข้อมูลโค้ดต่อไปนี้:

public static  void sort(List collection) { if (collection instanceof List) { // sort strings differently } // omitted }

จากนั้นเราได้รับข้อผิดพลาดในการคอมไพล์นี้:

error: illegal generic type for instanceof if (collection instanceof List) { ^

ในทางเทคนิคเราได้รับอนุญาตให้ใช้instanceofร่วมกับ reified เท่านั้นประเภทใน Java ประเภทจะถูก reified ถ้าข้อมูลประเภทอยู่ที่รันไทม์

ประเภท reified ใน Java มีดังนี้:

  • ประเภทดั้งเดิมเช่นint
  • คลาสและอินเทอร์เฟซที่ไม่ใช่แบบทั่วไปเช่นStringหรือRandom
  • ประเภททั่วไปซึ่งทุกประเภทเป็นสัญลักษณ์แทนแบบไม่ผูกมัดเช่นSetหรือMap
  • ประเภทดิบเช่นรายการหรือ HashMap
  • อาร์เรย์ประเภทอื่น ๆ ที่ปรับเปลี่ยนได้เช่นString [], List []หรือMap []

เนื่องจากพารามิเตอร์ประเภททั่วไปไม่ได้รับการแก้ไขเราจึงไม่สามารถใช้พารามิเตอร์เหล่านี้ได้:

public static  boolean isOfType(Object input) { return input instanceof T; // won't compile }

อย่างไรก็ตามเป็นไปได้ที่จะทดสอบกับสิ่งต่างๆเช่นรายการ :

if (collection instanceof List) { // do something }

7. สรุป

ในบทช่วยสอนนี้เราได้เรียนรู้เกี่ยวกับอินสแตนซ์ของตัวดำเนินการและวิธีการใช้งาน ตัวอย่างโค้ดที่สมบูรณ์มีอยู่ใน GitHub