อินสแตนซ์ของ Vs getClass ()


114

ฉันเห็นประสิทธิภาพที่เพิ่มขึ้นเมื่อใช้งานgetClass()และ==ดำเนินการมากกว่าinstanceOfตัวดำเนินการ

Object  str = new Integer("2000");

long starttime = System.nanoTime();

if(str instanceof String) {
    System.out.println("its string");
} else {
    if (str instanceof Integer) {
        System.out.println("its integer");

    }
}

System.out.println((System.nanoTime()-starttime));

starttime = System.nanoTime();

if(str.getClass() == String.class) {
    System.out.println("its string in equals");
} else {
    if(str.getClass() == Integer.class) {
        System.out.println("its integer");
    }
}

System.out.println((System.nanoTime()-starttime));

มีแนวทางใดบ้างที่จะใช้getClass()หรือinstanceOf?

กำหนดสถานการณ์: ฉันรู้ว่าการเรียนที่แน่นอนที่จะจับคู่, ที่อยู่String, Integer(เหล่านี้เรียนสุดท้าย) ฯลฯ

การใช้instanceOfตัวดำเนินการไม่ดีหรือไม่


3
นี่คือคำอธิบายใน: stackoverflow.com/questions/596462/...
Clement P

2
วิธีการจับเวลาของคุณทำให้เกิดความล่าช้าเกินจริงและให้ผลลัพธ์ของเวลาที่ไม่ถูกต้อง สลับลำดับที่คุณทำเช็คแล้วคุณจะเห็นว่าเช็คแรกที่คุณทำ (== หรือ instanceof) จะยาวกว่าเสมอ ฉันเดาว่ามันคือ println () s คุณไม่ควรรวมสิ่งนั้นไว้ในช่วงเวลาของคุณ
kurtzmarc

แยกความคิดเห็นเพียงครั้งเดียวเพื่อเปรียบเทียบประสิทธิภาพให้ใช้การวนซ้ำหลายรอบ (เช่น 10,000) เพื่อปรับปรุงความแม่นยำ การวิงวอนเพียงครั้งเดียวไม่ใช่มาตรการที่ดี
martins.tuga

คำตอบ:


139

เหตุผลที่ประสิทธิภาพของinstanceofและgetClass() == ...แตกต่างกันคือพวกเขากำลังทำสิ่งที่แตกต่างกัน

  • instanceofการทดสอบว่าอ้างอิงวัตถุที่อยู่ด้านซ้ายมือ (LHS) เป็นตัวอย่างของประเภททางด้านขวามือ (RHS) หรือชนิดย่อยบางส่วน

  • getClass() == ... ทดสอบว่าประเภทนั้นเหมือนกันหรือไม่

ดังนั้นคำแนะนำคือละเว้นปัญหาด้านประสิทธิภาพและใช้ทางเลือกอื่นที่ให้คำตอบที่คุณต้องการ

การใช้ตัวinstanceOfดำเนินการไม่ดีหรือไม่?

ไม่จำเป็น. การใช้อย่างใดอย่างหนึ่งมากเกินไปinstanceOfหรือgetClass() อาจเป็น "กลิ่นของการออกแบบ" หากคุณไม่ระมัดระวังคุณจะได้รับการออกแบบที่การเพิ่มคลาสย่อยใหม่ส่งผลให้โค้ดทำงานซ้ำได้จำนวนมาก ในสถานการณ์ส่วนใหญ่แนวทางที่ต้องการคือการใช้ความหลากหลาย

อย่างไรก็ตามมีบางกรณีที่สิ่งเหล่านี้ไม่ใช่ "กลิ่นดีไซน์" ตัวอย่างเช่นequals(Object)คุณต้องทดสอบประเภทจริงของอาร์กิวเมนต์และส่งคืนfalseหากไม่ตรงกัน getClass()นี้จะทำดีที่สุดโดยใช้


คำศัพท์เช่น "แนวทางปฏิบัติที่ดีที่สุด" "แนวทางปฏิบัติที่ไม่ดี" "กลิ่นการออกแบบ" "ปฏิปักษ์" และอื่น ๆ ควรใช้อย่าง จำกัด และปฏิบัติด้วยความสงสัย พวกเขาสนับสนุนการคิดแบบขาวดำ เป็นการดีกว่าที่จะใช้วิจารณญาณในบริบทแทนที่จะใช้ความเชื่อเพียงอย่างเดียว เช่นสิ่งที่มีคนกล่าวว่าเป็น "แนวทางปฏิบัติที่ดีที่สุด"


@StephenC อย่างที่บอกคือcode smellต้องใช้อย่างใดอย่างหนึ่ง นั่นหมายความว่ามันเป็นผลมาจากการออกแบบที่ไม่ดี (ไม่ใช่รูปแบบหลายรูปแบบ) ที่ทำให้คุณต้องใช้อย่างใดอย่างหนึ่ง ฉันสามารถสรุปการใช้งานอย่างใดอย่างหนึ่งด้วยวิธีนี้ได้หรือไม่?
เปลี่ยนแปลงมากเกินไป

@overexchange - 1) ฉันบอกว่า "ใช้มากเกินไป" ไม่ใช่ "ใช้" 2) นอกเหนือจากนั้นฉันไม่เข้าใจสิ่งที่คุณถาม "อนุมานการใช้งาน ... " หมายความว่าอย่างไร ??? โค้ดใช้สิ่งเหล่านี้หรือไม่
Stephen C

ฉันสรุปได้ว่าการใช้instanceof& getClass()กลายเป็นภาพเนื่องจากการออกแบบที่ไม่ดีที่มีอยู่ (ไม่ใช่ความหลากหลาย) ของรหัส ฉันถูกไหม?
เปลี่ยนแปลงมากเกินไป

5
@overexchange - คุณไม่สามารถอนุมานได้อย่างถูกต้องว่าการใช้instanceof(ตัวอย่าง) ทั้งหมดเป็นการออกแบบที่ไม่ดี มีสถานการณ์ที่อาจเป็นทางออกที่ดีที่สุด เหมือนกันสำหรับgetClass(). ผมจะทำซ้ำที่ผมกล่าวว่า"มากเกินไป"และไม่ใช่"การใช้งาน" ทุกกรณีจะต้องได้รับการตัดสินจากข้อดีของมัน ... ไม่ใช่โดยการใช้กฎเกณฑ์บางอย่างที่ไร้เหตุผลอย่างสุ่มสี่สุ่มห้า
Stephen C

44

คุณต้องการที่จะตรงกับชั้นเรียนตรงเช่นการจับคู่เท่านั้นFileInputStreamแทน subclass ใดFileInputStream? ถ้าเป็นเช่นนั้นให้ใช้getClass()และ==. โดยปกติฉันจะทำในส่วนequalsนี้เพื่อไม่ให้อินสแตนซ์ของ X เท่ากับอินสแตนซ์ของคลาสย่อยของ X มิฉะนั้นคุณอาจมีปัญหาเรื่องสมมาตรที่ยุ่งยาก ในทางกลับกันสิ่งนี้มักจะมีประโยชน์มากกว่าสำหรับการเปรียบเทียบว่าวัตถุสองชิ้นมีคลาสเดียวกันมากกว่าคลาสใดคลาสหนึ่ง

instanceofมิฉะนั้นการใช้งาน โปรดทราบว่าgetClass()คุณจะต้องตรวจสอบให้แน่ใจว่าคุณมีการอ้างอิงที่ไม่ใช่ค่าว่างเพื่อเริ่มต้นด้วยหรือคุณจะได้รับ a NullPointerExceptionในขณะที่instanceofจะส่งคืนfalseหากตัวถูกดำเนินการตัวแรกเป็นโมฆะ

โดยส่วนตัวแล้วฉันคิดว่าinstanceofเป็นสำนวนมากกว่า - แต่การใช้อย่างใดอย่างหนึ่งอย่างกว้างขวางเป็นกลิ่นการออกแบบในกรณีส่วนใหญ่


18

ฉันรู้ว่ามันถูกถามมาระยะหนึ่งแล้ว แต่เมื่อวานฉันได้เรียนรู้ทางเลือกอื่น

เราทุกคนรู้ว่าคุณทำได้:

if(o instanceof String) {   // etc

แต่จะเกิดอะไรขึ้นถ้าคุณไม่รู้ว่ามันต้องเป็นคลาสประเภทไหน? คุณไม่สามารถทำได้โดยทั่วไป:

if(o instanceof <Class variable>.getClass()) {   

เนื่องจากมีข้อผิดพลาดในการคอมไพล์
นี่เป็นทางเลือกแทน - isAssignableFrom ()

ตัวอย่างเช่น:

public static boolean isASubClass(Class classTypeWeWant, Object objectWeHave) {

    return classTypeWeWant.isAssignableFrom(objectWeHave.getClass())
}

8
อย่าใช้isAssignableFrom. วิธีที่ถูกต้องในการเขียนใช้สะท้อนเป็นo instanceof String String.getClass().isInstance(o)javadoc ถึงกับพูดอย่างนั้น: วิธีนี้เทียบเท่ากับinstanceofตัวดำเนินการภาษา Java แบบไดนามิก
Andreas

3

getClass () มีข้อ จำกัด ที่ว่าอ็อบเจ็กต์จะเท่ากับอ็อบเจ็กต์อื่น ๆ ในคลาสเดียวกันเท่านั้นซึ่งเป็นประเภทรันไทม์เดียวกันดังแสดงในเอาต์พุตของโค้ดด้านล่าง:

class ParentClass{
}
public class SubClass extends ParentClass{
    public static void main(String []args){
        ParentClass parentClassInstance = new ParentClass();
        SubClass subClassInstance = new SubClass();
        if(subClassInstance instanceof ParentClass){
            System.out.println("SubClass extends ParentClass. subClassInstance is instanceof ParentClass");
        }
        if(subClassInstance.getClass() != parentClassInstance.getClass()){
            System.out.println("Different getClass() return results with subClassInstance and parentClassInstance ");
        }
    }
}

ขาออก:

SubClass ขยาย ParentClass subClassInstance เป็นอินสแตนซ์ของ ParentClass

getClass () ที่แตกต่างกันส่งคืนผลลัพธ์ด้วย subClassInstance และ parentClassInstance

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