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