ตรวจสอบว่า Class Object เป็นคลาสย่อยของ Class Object อื่นใน Java


197

ฉันกำลังเล่นกับ API การสะท้อนของ Java และพยายามจัดการบางฟิลด์ ตอนนี้ฉันติดอยู่กับการระบุประเภทของเขตข้อมูลของฉัน myField.getType().equals(String.class)สตริงเป็นเรื่องง่ายเพียงแค่ทำ เช่นเดียวกับคลาสอื่นที่ไม่ได้รับ แต่ฉันจะตรวจสอบคลาสที่ได้รับได้อย่างไร เช่นLinkedListเป็น subclass Listของ ฉันไม่สามารถหาใด ๆisSubclassOf(...)หรือextends(...)วิธีการ ฉันจำเป็นต้องเดินผ่านทั้งหมดgetSuperClass()และค้นหา supeclass ของฉันด้วยตัวเองหรือไม่?


11
LinkedListไม่ได้เป็น subclass Listของ มันเป็นการดำเนินงานListของ
TJ Crowder

2
ประเภทย่อยอาจเป็นคำที่ดีกว่า
jpaugh

คำตอบ:


403

คุณต้องการวิธีนี้:

boolean isList = List.class.isAssignableFrom(myClass);

โดยทั่วไปList(ด้านบน) ควรถูกแทนที่ด้วยsuperclassและmyClassควรถูกแทนที่ด้วยsubclass

จากJavaDoc :

กำหนดว่าคลาสหรืออินเตอร์เฟซที่แสดงโดยClassวัตถุนี้จะเหมือนกันหรือเป็น superclass หรือ superinterface ของชั้นหรืออินเตอร์เฟซที่แสดงโดยClassพารามิเตอร์ที่ระบุ มันจะกลับมาtrueถ้าใช่; falseมิฉะนั้นก็จะส่งกลับ หากClassวัตถุนี้แสดงให้เห็นถึงประเภทดั้งเดิมวิธีการนี้จะส่งกลับtrueถ้าClassพารามิเตอร์ที่ระบุเป็นสิ่งที่Classวัตถุนี้; falseมิฉะนั้นก็จะส่งกลับ

อ้างอิง:


ที่เกี่ยวข้อง:

a) ตรวจสอบว่า Object เป็นตัวอย่างของ Class หรือ Interface (รวมถึง subclasses) ที่คุณรู้จัก ณ เวลารวบรวมหรือไม่:

boolean isInstance = someObject instanceof SomeTypeOrInterface;

ตัวอย่าง:

assertTrue(Arrays.asList("a", "b", "c") instanceof List<?>);

b) ตรวจสอบว่า Object เป็นอินสแตนซ์ของ Class หรือ Interface (รวมถึง subclasses) ที่คุณรู้ตอนรันไทม์:

Class<?> typeOrInterface = // acquire class somehow
boolean isInstance = typeOrInterface.isInstance(someObject);

ตัวอย่าง:

public boolean checkForType(Object candidate, Class<?> type){
    return type.isInstance(candidate);
}

21
หมายเหตุรูปแบบ: SUPERCLASS.isAssignableFrom(SUBCLASS)สิ่งนี้ทำให้ฉันสับสนก่อนจริง ๆ แล้วมันค่อนข้างชัดเจนเมื่อพิจารณาการตั้งชื่อ
codepleb

7
@TrudleR ฉันเห็นด้วย บางอย่างSUPERCLASS.isExtendedBy(SUBCLASS)จะง่ายกว่าที่จะเข้าใจ
Sean Patrick Floyd

@SeanPatrickFloyd จริง ๆ แล้วisExtendedByเป็นชื่อที่ไม่ดีเท่าที่CLASS.isAssignableFrom(CLASS)จะเป็นจริง (และดังนั้นCLASS.isExtendedBy(CLASS)เช่นกัน) นี่จะไม่ใช่สิ่งที่ฉันคาดไว้
Qw3ry

@ Qw3ry ใช่ฉันสมมติว่านอกจากนี้ยังเป็นสิ่งที่ผู้เขียนคิดว่า Api :-)
ฌอนแพทริคฟลอยด์

25

ตัวเลือกอื่นคือตัวอย่างของ:

Object o =...
if (o instanceof Number) {
  double d = ((Number)o).doubleValue(); //this cast is safe
}

โทรดี (+1) และนอกจากนี้ยังมีการรวมกันของกลไกทั้งสอง: Class.isInstance(object) download.oracle.com/javase/6/docs/api/java/lang/…
ฌอนแพทริคฟลอยด์

5
สิ่งนี้จะบอกเป็นนัยว่าคุณFieldเริ่มต้น แต่ฉันแค่ต้องการ "ดู" ชั้นเรียนของฉันและสาขาของมันไม่ต้องการที่จะ "ลองพวกเขา"
craesh

ฉันเห็นวิธีนี้สะอาดและชัดเจนกว่าวิธี "isAssignableFrom" ในกรณีที่คุณต้องตรวจสอบแผนผังการสืบทอดของวัตถุ
cbuchart

โปรดทราบว่าinstanceofยังใช้งานได้กับผู้ปกครอง (ในกรณีนี้Number) ไม่เพียง แต่เด็กเท่านั้น
lukaszrys

9

instanceof ใช้งานได้บนอินสแตนซ์เช่นบน Objects บางครั้งคุณต้องการทำงานโดยตรงกับชั้นเรียน ในกรณีนี้คุณสามารถใช้วิธีasSubClassของคลาส Class ตัวอย่างบางส่วน:

1)

    Class o=Object.class;
    Class c=Class.forName("javax.swing.JFrame").asSubclass(o);

สิ่งนี้จะผ่านได้อย่างราบรื่นเนื่องจาก JFrame เป็นคลาสย่อยของ Object c จะมีวัตถุ Class ที่เป็นตัวแทนของชั้น JFrame

2)

    Class o=JButton.class;
    Class c=Class.forName("javax.swing.JFrame").asSubclass(o);

สิ่งนี้จะเรียกใช้java.lang.ClassCastExceptionเนื่องจาก JFrame ไม่ใช่คลาสย่อยของ JButton c จะไม่สามารถเริ่มต้นได้

3)

    Class o=Serializable.class;
    Class c=Class.forName("javax.swing.JFrame").asSubclass(o);

สิ่งนี้จะผ่านได้อย่างราบรื่นเนื่องจาก JFrame ใช้ส่วนต่อประสาน java.io.Serializable c จะมีวัตถุ Class ที่เป็นตัวแทนของชั้น JFrame

แน่นอนว่าจำเป็นต้องรวมการนำเข้าที่จำเป็น


5

สิ่งนี้ใช้ได้กับฉัน:

protected boolean isTypeOf(String myClass, Class<?> superClass) {
    boolean isSubclassOf = false;
    try {
        Class<?> clazz = Class.forName(myClass);
        if (!clazz.equals(superClass)) {
            clazz = clazz.getSuperclass();
            isSubclassOf = isTypeOf(clazz.getName(), superClass);
        } else {
            isSubclassOf = true;
        }

    } catch(ClassNotFoundException e) {
        /* Ignore */
    }
    return isSubclassOf;
}

1
ใช้งานได้ดี แต่คุณอาจต้องเพิ่มการตรวจสอบว่างหลังจาก clazz = clazz.getSuperclass () ในกรณีที่คุณกด java.lang.Object ผู้ที่ไม่มีคลาสซูเปอร์
Jonas Pedersen

4

นี่เป็นคำตอบของ @ schuttek รุ่นปรับปรุง มันได้รับการปรับปรุงเพราะมันคืนค่าเท็จสำหรับ primitives อย่างถูกต้อง (เช่น isSubclassOf (int.class, Object.class) => false) และจัดการอินเตอร์เฟสได้อย่างถูกต้อง (เช่น isSubclassOf (HashMap.class, Map.class) => true

static public boolean isSubclassOf(final Class<?> clazz, final Class<?> possibleSuperClass)
{
    if (clazz == null || possibleSuperClass == null)
    {
        return false;
    }
    else if (clazz.equals(possibleSuperClass))
    {
        return true;
    }
    else
    {
        final boolean isSubclass = isSubclassOf(clazz.getSuperclass(), possibleSuperClass);

        if (!isSubclass && clazz.getInterfaces() != null)
        {
            for (final Class<?> inter : clazz.getInterfaces())
            {
                if (isSubclassOf(inter, possibleSuperClass))
                {
                    return true;
                }
            }
        }

        return isSubclass;
    }
}

3

วิธีการเรียกซ้ำเพื่อตรวจสอบว่า a Class<?>เป็นคลาสย่อยของอีกClass<?>...

รุ่นปรับปรุงของ@To กระ 's คำตอบ :

protected boolean isSubclassOf(Class<?> clazz, Class<?> superClass) {
    if (superClass.equals(Object.class)) {
        // Every class is an Object.
        return true;
    }
    if (clazz.equals(superClass)) {
        return true;
    } else {
        clazz = clazz.getSuperclass();
        // every class is Object, but superClass is below Object
        if (clazz.equals(Object.class)) {
            // we've reached the top of the hierarchy, but superClass couldn't be found.
            return false;
        }
        // try the next level up the hierarchy.
        return isSubclassOf(clazz, superClass);
    }
}

3

// มรดก

    class A {
      int i = 10;
      public String getVal() {
        return "I'm 'A'";
      }
    }

    class B extends A {
      int j = 20;
      public String getVal() {
        return "I'm 'B'";
      }
    }

    class C extends B {
        int k = 30;
        public String getVal() {
          return "I'm 'C'";
        }
    }

// วิธี

    public static boolean isInheritedClass(Object parent, Object child) {
      if (parent == null || child == null) {
        return false;
      } else {
        return isInheritedClass(parent.getClass(), child.getClass());
      }
    }

    public static boolean isInheritedClass(Class<?> parent, Class<?> child) {
      if (parent == null || child == null) {
        return false;
      } else {
        if (parent.isAssignableFrom(child)) {
          // is child or same class
          return parent.isAssignableFrom(child.getSuperclass());
        } else {
          return false;
        }
      }
    }

// ทดสอบรหัส

    System.out.println("isInheritedClass(new A(), new B()):" + isInheritedClass(new A(), new B()));
    System.out.println("isInheritedClass(new A(), new C()):" + isInheritedClass(new A(), new C()));
    System.out.println("isInheritedClass(new A(), new A()):" + isInheritedClass(new A(), new A()));
    System.out.println("isInheritedClass(new B(), new A()):" + isInheritedClass(new B(), new A()));


    System.out.println("isInheritedClass(A.class, B.class):" + isInheritedClass(A.class, B.class));
    System.out.println("isInheritedClass(A.class, C.class):" + isInheritedClass(A.class, C.class));
    System.out.println("isInheritedClass(A.class, A.class):" + isInheritedClass(A.class, A.class));
    System.out.println("isInheritedClass(B.class, A.class):" + isInheritedClass(B.class, A.class));

//ผลลัพธ์

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