จำเป็นต้องตรวจสอบ null ก่อนโทร instanceof หรือไม่?


1354

จะnull instanceof SomeClassกลับมาfalseหรือโยนNullPointerException?


นอกจากนี้ยังเป็น 'สำคัญ' หรืออย่างน้อยมีประโยชน์มากในฐานะที่เป็น 'แนวปฏิบัติที่ดีที่สุด' สำหรับการเริ่มต้น (หรือเร็วมาก) สำหรับการเปรียบเทียบหรือเท่ากับหรือวิธีการที่คล้ายกันที่ออกแบบมาเพื่อให้ประสบความสำเร็จในวัตถุที่ไม่ใช่วัตถุประเภทเดียวกันเท่านั้น ปกป้องคุณจาก 'คดีที่โง่' ในบรรทัดเดียว รหัสน้อย = ข้อผิดพลาดน้อย

13
การชั่งน้ำหนักใน "มีประโยชน์หรือไม่?" การถกเถียง - ฉันไม่เคยเขียนโค้ด Java ของตัวเอง (ดังนั้นจึงไม่สามารถรู้ได้อย่างง่ายดายว่าสเป็คอยู่ที่ใดและการรวบรวมการทดสอบจะไม่สำคัญมาก) แต่ตอนนี้ฉันกำลังแปลง Java เป็น JavaScript ด้วยตนเอง รหัสของฉันล้มเหลวในการอ้างอิงเป็นโมฆะและ googling นี้ให้ฉันดูคำตอบที่ยอมรับซึ่งยืนยันว่ามันเป็นพฤติกรรมที่คาดหวังและฉันก็หายไปตรวจสอบเป็นนัยโดยนัย มีประโยชน์มากในกรณีของฉัน
Scott Mermelstein

คำตอบ:


1838

ไม่ไม่จำเป็นต้องตรวจสอบ null ก่อนใช้งาน instanceof

การแสดงออกx instanceof SomeClassคือfalseถ้าเป็นxnull

จากข้อกำหนดภาษา Java, ส่วน 15.20.2, "ตัวดำเนินการเปรียบเทียบอินสแตนซ์ของ" :

"ณ รันไทม์ผลลัพธ์ของ instanceofโอเปอเรเตอร์คือtrueถ้าค่าของRelational Expression ไม่ได้nullและการอ้างอิงอาจส่งไปยังReferenceType โดยไม่ต้องเพิ่ม a ClassCastExceptionมิฉะนั้นจะเกิดผลลัพธ์false"

ดังนั้นถ้าตัวถูกดำเนินการเป็นโมฆะผลลัพธ์จะเป็นเท็จ


377
คำตอบนี้ถูกต้องมากกว่าtry itเพราะพฤติกรรมในปัจจุบันไม่ได้เป็นเช่นเดียวกับพฤติกรรมการรับประกัน
ลุค

3
คำถามนี้เข้ามาในระหว่างบทของ Joshua Bloch เกี่ยวกับความเสมอภาคของวัตถุในEffective Java- amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683
Kevin Meredith

17
โดยเฉพาะอย่างยิ่งในรายการที่ 8 เขาบันทึกว่าในเมธอด equals () หนึ่งอินสแตนซ์ของโอเปอเรเตอร์ทำหน้าที่สองประการ - มันตรวจสอบว่าอาร์กิวเมนต์นั้นเป็นทั้งแบบไม่เป็นโมฆะและชนิดที่ถูกต้อง "... [S] o คุณไม่จำเป็นต้องมีการตรวจสอบโมฆะแยกต่างหาก"
Andy Thomas

2
@BenThurley - instanceofผู้ดำเนินการของ Java เป็นส่วนหนึ่งของ Java 1.0 เผยแพร่เกือบ 20 ปีที่ผ่านมา การเปลี่ยนพฤติกรรมในขณะนี้ในลักษณะที่จะทำลายรหัสที่มีอยู่นั้นไม่น่าเป็นไปได้โดยขาดประโยชน์บางอย่างที่มากกว่าค่าใช้จ่ายจำนวนมาก ยี่สิบปีที่ผ่านมาอาจจะมีข้อโต้แย้งสำหรับการคืนค่าจริงถ้าอาร์กิวเมนต์สามารถโยนหรือโยนข้อยกเว้นสำหรับอาร์กิวเมนต์ว่าง แต่คำจำกัดความเหล่านั้นจะต้องมีการตรวจสอบ null แยกต่างหาก
Andy Thomas

3
@BenThurley - พฤติกรรมรับประกันโดยข้อกำหนดจาวาในอดีตและปัจจุบัน ฉันคิดว่าจุดของลุคกล่าวถึงข้อ จำกัด ของการทดลองเพื่อกำหนดพฤติกรรมที่รับประกันได้ในปัจจุบัน
Andy Thomas

267

ใช้อ้างอิงโมฆะเป็นตัวถูกดำเนินการครั้งแรกที่ผลตอบแทนinstanceoffalse


268
(และตอนนี้ใช้เวลา 10 วินาทีในการค้นหาคำถามนี้ใน Google)
PL_kolek

73

คำถามที่ดีมากแน่นอน ฉันแค่ลองเอง

public class IsInstanceOfTest {

    public static void main(final String[] args) {

        String s;

        s = "";

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));

        s = null;

        System.out.println((s instanceof String));
        System.out.println(String.class.isInstance(s));
    }
}

พิมพ์

true
true
false
false

JLS / 15.20.2 ตัวดำเนินการเปรียบเทียบชนิดของอินสแตนซ์

ในเวลาทำงานผลมาจากการที่instanceofผู้ประกอบการคือtrueถ้าค่าของRelationalExpressionไม่ได้nullและการอ้างอิงอาจถูกโยนไปReferenceTypeClassCastExceptionโดยไม่ต้องยก falseมิฉะนั้นผลที่ได้คือ

API / Class # isInstance (Object)

ถ้าClassวัตถุนี้แสดงถึงอินเตอร์เฟสวิธีการนี้จะคืนค่าtrueถ้าคลาสหรือซูเปอร์คลาสใด ๆ ของObjectอาร์กิวเมนต์ที่ระบุใช้อินเทอร์เฟซนี้ มันกลับมาเป็นfalseอย่างอื่น หากนี่วัตถุหมายถึงชนิดดั้งเดิมวิธีนี้ผลตอบแทนClassfalse


ชนิดของความสับสน s เป็นสตริงเพราะมันบอกว่า "String s" s ไม่ใช่สตริงเพราะมันเป็นโมฆะ แล้วนรกคืออะไร?
ไก่วัง

1
@KaiWang sเป็นเพียงตัวแปรอ้างอิงวัตถุ มันอาจอ้างถึงวัตถุที่มีอยู่จริง ( "") หรืออาจอ้างอิงถึง (ที่) nullอ้างอิงตามตัวอักษร
Jin Kwon

ฉันยังสับสนอยู่ s อาจเป็นโมฆะในตอนนี้ แต่สามารถชี้ไปที่อินสแตนซ์ของสตริงได้ในภายหลังเท่านั้น ไม่สามารถชี้ไปยังได้เหมือน Integer ดังนั้นมันจึงยังคงเป็นสตริงแม้ว่ามันจะเป็นโมฆะ ก็ไม่ได้ทำให้ความรู้สึกมาก ...
ไก่วัง

@KaiWang คุณกำลังสับสนประเภทตัวแปรกับประเภทของวัตถุจริง ตัวแปรไม่ใช่อินสแตนซ์ พวกมันเป็นตัวชี้อย่างมีประสิทธิภาพ nullไม่ใช่ข้อมูลสตริงไม่ว่าตัวแปรจะชี้ไปที่ใด ตัวอย่างเช่นs instanceof Stringไม่เหมือนกัน field.getType().equals(String.class)
Matthew อ่าน

@KaiWang คุณต้องคิดว่าในการโทรได้รับการแทนที่ด้วยค่าจริงเพื่อที่จะกลายเป็นและ คิดเกี่ยวกับมันเช่นนี้อาจทำให้รู้สึกมากขึ้น s instanceof Strings"" instanceof Stringnull instanceof String
Timo Türschmann


16

เช่นเดียวกับอาหารอันโอชะ :

แม้จะกลับมา(((A)null)instanceof A)false


(หากการพิมพ์ดีดnullน่าแปลกใจบางครั้งคุณต้องทำเช่นในสถานการณ์เช่นนี้:

public class Test
{
  public static void test(A a)
  {
    System.out.println("a instanceof A: " + (a instanceof A));
  }

  public static void test(B b) {
    // Overloaded version. Would cause reference ambiguity (compile error)
    // if Test.test(null) was called without casting.
    // So you need to call Test.test((A)null) or Test.test((B)null).
  }
}

ดังนั้นTest.test((A)null)จะพิมพ์a instanceof A: false)


PS: ถ้าคุณกำลังจ้างงานอย่าใช้คำถามนี้เป็นคำถามสัมภาษณ์งาน : D


7

ไม่ Java literal nullไม่ใช่ตัวอย่างของคลาสใด ๆ ดังนั้นจึงไม่สามารถเป็นอินสแตนซ์ของคลาสใดก็ได้ instanceof จะกลับอย่างใดอย่างหนึ่งfalseหรือtrueดังนั้น<referenceVariable> instanceof <SomeClass>ผลตอบแทนfalseเมื่อreferenceVariableค่าเป็นโมฆะ


5
ที่เสียงคำอธิบายวงกลมแปลก ... แต่ฉันรู้ว่าสิ่งที่คุณหมายถึง :-)
คริส

@Kris ty สำหรับความคิดเห็นที่ฉันได้รับสิ่งที่คุณหมายถึง :) แก้ไขคำตอบเล็กน้อย :)
นักพัฒนา Marius Žilėnas

1

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

ณ รันไทม์ผลลัพธ์ของinstanceofโอเปอเรเตอร์เป็นจริงถ้าค่าของนิพจน์เชิงสัมพันธ์ไม่ได้nullและการอ้างอิงอาจถูกส่งไปยังชนิดของการอ้างอิงโดยไม่เพิ่มข้อยกเว้นการส่งคลาส

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

ลองพิจารณาตัวอย่างด้านล่าง

public static void main(String[] args) {
         if(lista != null && lista instanceof ArrayList) {                     //Violation
                System.out.println("In if block");
         }
         else {
                System.out.println("In else block");
         }
}

การใช้งานที่ถูกต้องของinstanceofที่แสดงด้านล่าง

public static void main(String[] args) {
      
         if(lista instanceof ArrayList){                     //Correct way
                  System.out.println("In if block");
         }
            else {
                 System.out.println("In else block");
         }  
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.