java: Class.isInstance vs Class.isAssignableFrom


232

อนุญาตclazzเป็นบางส่วนClassและมีบางobjObject

คือ

clazz.isAssignableFrom(obj.getClass())

เช่นเดียวกับเสมอ

clazz.isInstance(obj)

?

ถ้าไม่แตกต่างกันอย่างไร


26
ถ้า obj == null, อันที่สองจะคืนค่าเป็นเท็จ, อันแรกไม่ได้ ;)
Peter Lawrey

21
@PeterLawrey เป็นครั้งแรกที่จะโยนถ้าNullPointerException obj == null
ryvantage

พบคำตอบบางอย่างจากตัวอย่างจาก hrere: mytechnotes.biz/2012/07/…
Paramesh Korrakuti

4
สำหรับผู้อ่าน: คุณกำลังจะเข้าสู่หลุมดำมืดและลึกซึ่งคุณจะไม่มีวันรอด ความแตกต่างไม่มีที่สิ้นสุด ยอมแพ้ในขณะที่คุณยังสามารถทำได้: stackoverflow.com/q/496928/1599699
Andrew

@ParameshKorrakuti ชื่อโดเมนกำลังเปลี่ยนเป็นtshikatshikaaa.blogspot.com/2012/07/30
Jérôme Verstrynge

คำตอบ:


222

clazz.isAssignableFrom(Foo.class)จะเป็นจริงเมื่อใดก็ตามที่ชั้นแทนด้วยclazzวัตถุเป็น superclass หรือ superinterface Fooของ

clazz.isInstance(obj)จะเป็นจริงเมื่อใดก็ตามที่วัตถุที่เป็นตัวอย่างของการเรียนobjclazz

นั่นคือ:

clazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj)

เป็นจริงเสมอตราบclazzและobjมี nonnull


3
นี่เป็นกรณีที่ Foo ไม่เหมือนกับ clazz ซึ่งในกรณีนี้มันจะคืนค่าจริง: Pauls คำตอบที่ได้รับคะแนนสูงสุดด้านล่างแก้ไขสิ่งนี้
Rhubarb

3
ฉันยอมรับว่าเมื่อ clazz เป็น Foo แล้ว clazz.isAssignableFrom (Foo.class) นั้นเป็นจริง ฉันพูดอย่างอื่นที่ไหน
uckelman

5
@Gili นี่ไม่ใช่สิ่งที่ uckelman พูด โปรดอ่านคำตอบของเขาอีกครั้ง
Puce

2
Byte b = 3; Comparable.class.isAssignableFrom(b.getClass()) == Comparable.class.isInstance(b)); -> มันเป็นเรื่องจริงสำหรับอินเทอร์เฟซ
Puce

1
วิชา: ถ้าobjเป็นnullแล้วclazz.isAssignableFrom(obj.getClass()) == clazz.isInstance(obj)จะโยนและไม่กลับมาNullPointerException true
Andrew Macheret

196

คำตอบทั้งสองอยู่ใน ballpark แต่ไม่มีคำตอบที่สมบูรณ์

MyClass.class.isInstance(obj)สำหรับการตรวจสอบอินสแตนซ์ มันกลับเป็นจริงเมื่อ obj พารามิเตอร์ไม่เป็นโมฆะและสามารถโยนไปโดยไม่ต้องยกMyClass ClassCastExceptionกล่าวอีกนัยหนึ่ง obj เป็นตัวอย่างของMyClassคลาสย่อยหรือ

MyClass.class.isAssignableFrom(Other.class)จะกลับมาจริงถ้าMyClassเป็นเช่นเดียวกับหรือ superclass หรือ superinterface Otherของ Otherสามารถเป็นคลาสหรืออินเทอร์เฟซ มันตอบจริงถ้าสามารถแปลงเป็นOtherMyClass

รหัสเล็กน้อยที่จะแสดง:

public class NewMain
{
    public static void main(String[] args)
    {
        NewMain nm = new NewMain();
        nm.doit();
    }

    class A { }

    class B extends A { }

    public void doit()
    {
        A myA = new A();
        B myB = new B();
        A[] aArr = new A[0];
        B[] bArr = new B[0];

        System.out.println("b instanceof a: " + (myB instanceof A)); // true
        System.out.println("b isInstance a: " + A.class.isInstance(myB)); //true
        System.out.println("a isInstance b: " + B.class.isInstance(myA)); //false
        System.out.println("b isAssignableFrom a: " + A.class.isAssignableFrom(B.class)); //true
        System.out.println("a isAssignableFrom b: " + B.class.isAssignableFrom(A.class)); //false
        System.out.println("bArr isInstance A: " + A.class.isInstance(bArr)); //false
        System.out.println("bArr isInstance aArr: " + aArr.getClass().isInstance(bArr)); //true
        System.out.println("bArr isAssignableFrom aArr: " + aArr.getClass().isAssignableFrom(bArr.getClass())); //true
    }
}

10
ทำไมในตัวอย่าง "b isAssignable จาก a:" แต่โค้ดคือA.class.isAssignableFrom(B.class)? ฉันสับสนด้วยผลลัพธ์ :)
Roman Truba

4
ummm ... ในตัวอย่างทั้งหมดของคุณ "instanceOf" จะคืนค่าจริง iff "isAssignableFrom" คืนค่าจริง ... ฉันไม่เห็นความแตกต่างในลักษณะนี้
นักพัฒนา android

2
ระวังข้อความที่พิมพ์ออกมาไม่ตรงกับรหัสและอาจทำให้สับสน ... ตัวอย่าง: "System.out.println (" b isAssignableFrom a: "+ A.class.isAssignableFrom (B.class));"
polster

21
@ พอลคำตอบก็คือไม่มีประโยชน์เพราะผู้อ่านสงสัยว่า "ความแตกต่างระหว่างวัตถุใด ๆ ที่เป็นตัวอย่างของคลาสย่อยของคลาสและประเภทของวัตถุที่สามารถแปลงเป็นชั้นได้หรือไม่" แน่นอนคุณจะเห็นว่าคุณได้ทิ้งคำถามไว้มากมายหลังจากอ่านคำตอบของคุณอย่างที่เขามีเมื่อมาถึงหน้านี้ คำตอบที่ดีกว่าจริง ๆ จะอธิบายความแตกต่าง (หรือขาดมัน) หากไม่มีความแตกต่างคำตอบควรระบุโดยตรงว่า "ไม่มีความแตกต่างในทางปฏิบัติ"
Aleksandr Dubinsky

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

6

ฉันคิดว่าผลลัพธ์สำหรับทั้งสองนั้นควรจะเหมือนกันเสมอ ความแตกต่างคือที่คุณต้องการตัวอย่างของการเรียนที่จะใช้isInstanceแต่เพียงวัตถุที่จะใช้ClassisAssignableFrom


นี่ไม่เป็นความจริง 100% แต่Comparable.class.isAssignableFrom(Byte.class) == true Byte.class.isInstance(Comparable.class) == falseกล่าวอีกนัยหนึ่งisInstance()ไม่ได้เป็นสมมาตรสำหรับอินเทอร์เฟซสำหรับคลาสย่อยเท่านั้น
Gili

6
@Gili: คุณได้รับมันผิดเล็กน้อย Byte.class.isInstance(Comparable.class)เป็นเท็จเพราะวัตถุที่ไม่ได้เป็นตัวอย่างของClass Byteการเปรียบเทียบที่ถูกต้องComparable.class.isAssignableFrom(Byte.class)คือComparable.class.isInstance((byte) 1)ซึ่งเป็นจริง
ColinD

1
ฉันไม่เห็นด้วย. หากคุณค้นหา Javadoc ของByteคุณจะค้นพบมันขยายNumberและเป็นชั้นเรียน จะไม่เทียบเท่ากับ(byte) 1 Byteอดีตเป็นแบบดั้งเดิม หลังคือคลาส
Gili

2
@Gili: Autoboxing ปลดเปลื้องดั้งเดิมbyteไปByteเพราะพารามิเตอร์ชนิดของคือisInstance Object
ColinD

2
ตกลง. จุดเริ่มต้นของฉันคือการโทรไม่ได้สมมาตรกันอย่างแท้จริง แต่เมื่ออ่านคำตอบของคุณอีกครั้งคุณไม่เคยยืนยันสิ่งนี้ดังนั้นคุณพูดถูก
Gili

6

เพื่อความกระชับเราสามารถเข้าใจ API ทั้งสองนี้ได้ดังนี้:

  1. X.class.isAssignableFrom(Y.class)

ถ้าXและYเป็นคลาสเดียวกันหรือXเป็นYซูเปอร์คลาสหรืออินเทอร์เฟซพิเศษให้คืนค่าจริงมิฉะนั้นเป็นเท็จ

  1. X.class.isInstance(y)

Say yเป็นตัวอย่างของคลาสYถ้าXและYเป็นคลาสเดียวกันหรือXเป็นYคลาส super หรืออินเตอร์เฟส super ให้คืนค่าจริงมิฉะนั้นจะเป็นเท็จ

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