Periksa apakah Obyek Kelas adalah subkelas dari Objek Kelas lain di Jawa

196

Saya bermain-main dengan API refleksi Java dan mencoba menangani beberapa bidang. Sekarang saya terjebak dengan mengidentifikasi jenis bidang saya. String itu mudah, lakukan saja myField.getType().equals(String.class). Hal yang sama berlaku untuk kelas non-turunan lainnya. Tetapi bagaimana saya memeriksa kelas turunan? Misalnya LinkedListsebagai subkelas dari List. Saya tidak dapat menemukan isSubclassOf(...)atau extends(...)metode. Apakah saya harus berjalan melalui semua getSuperClass()dan menemukan supeclass sendiri?

craesh
sumber
11
LinkedListbukan subkelas dari List. Ini merupakan implementasi dari List.
TJ Crowder
2
Sub-tipe mungkin istilah yang lebih baik
jpaugh

Jawaban:

402

Anda menginginkan metode ini:

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

di mana secara umum, List(di atas) harus diganti superclassdan myClassharus diganti dengansubclass

Dari JavaDoc :

Menentukan apakah kelas atau antarmuka yang diwakili oleh Classobjek ini adalah sama dengan, atau merupakan kelas super atau superinterface dari, kelas atau antarmuka diwakili oleh Classparameter yang ditentukan . Ia kembali truejika demikian; jika tidak kembali false. Jika Classobjek ini merupakan tipe primitif, metode ini kembali truejika Classparameter yang ditentukan adalah Classobjek ini ; jika tidak kembali false.

Referensi:


Terkait:

a) Periksa apakah Obyek adalah turunan dari Kelas atau Antarmuka (termasuk subclass) yang Anda tahu pada waktu kompilasi:

boolean isInstance = someObject instanceof SomeTypeOrInterface;

Contoh:

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

b) Periksa apakah Obyek adalah turunan dari Kelas atau Antarmuka (termasuk subclass) yang hanya Anda ketahui saat runtime:

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

Contoh:

public boolean checkForType(Object candidate, Class<?> type){
    return type.isInstance(candidate);
}
Sean Patrick Floyd
sumber
20
Perhatikan skemanya: SUPERCLASS.isAssignableFrom(SUBCLASS)Ini membingungkan saya dulu, meskipun sebenarnya jelas mempertimbangkan penamaannya.
codepleb
7
@ TrudleR saya setuju. Sesuatu seperti SUPERCLASS.isExtendedBy(SUBCLASS)akan lebih mudah dipahami
Sean Patrick Floyd
@SeanPatrickFloyd sebenarnya isExtendedByadalah nama yang buruk dan CLASS.isAssignableFrom(CLASS)benar (dan karenanya CLASS.isExtendedBy(CLASS)juga). Ini tidak akan seperti yang saya harapkan.
Qw3ry
@ Qw3saya ya, saya berasumsi itu juga yang dipikirkan penulis Api :-)
Sean Patrick Floyd
24

Pilihan lain adalah instanceof:

Object o =...
if (o instanceof Number) {
  double d = ((Number)o).doubleValue(); //this cast is safe
}
Landei
sumber
Panggilan bagus (+1). Dan kemudian ada juga kombinasi dari dua mekanisme: Class.isInstance(object) download.oracle.com/javase/6/docs/api/java/lang/…
Sean Patrick Floyd
5
Ini akan menyiratkan, bahwa Anda memulai itu Field. Tapi saya hanya ingin "melihat" kelas saya dan bidangnya, tidak ingin "mencobanya".
craesh
Saya melihat metode ini jauh lebih bersih dan lebih jelas daripada cara "isAssignableFrom", dalam hal ini Anda perlu memeriksa pohon warisan objek.
cbuchart
Ingatlah bahwa itu instanceofjuga berfungsi untuk orang tua (dalam hal ini Number) itu sendiri tidak hanya anak
lukaszrys
9

instanceof bekerja pada instance, yaitu pada Objects. Terkadang Anda ingin bekerja secara langsung dengan kelas. Dalam hal ini Anda dapat menggunakan metode asSubClass dari kelas Class. Beberapa contoh:

1)

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

ini akan berjalan dengan lancar karena JFrame adalah subclass dari Object. c akan berisi objek Class yang mewakili kelas JFrame.

2)

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

ini akan meluncurkan java.lang.ClassCastException karena JFrame BUKAN subclass dari JButton. c tidak akan diinisialisasi.

3)

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

ini akan berjalan dengan lancar karena JFrame mengimplementasikan antarmuka java.io.Serializable. c akan berisi objek Class yang mewakili kelas JFrame.

Tentu saja impor yang dibutuhkan harus dimasukkan.

Marco
sumber
5

Ini bekerja untuk saya:

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;
}
Untuk Kra
sumber
1
Berfungsi bagus, tetapi Anda mungkin harus menambahkan cek nol setelah clazz = clazz.getSuperclass () jika Anda menekan java.lang.Object yang tidak memiliki kelas super.
Jonas Pedersen
4

Ini adalah versi perbaikan dari jawaban @ schuttek. Ini ditingkatkan karena dengan benar mengembalikan false untuk primitif (mis. IsSubclassOf (int.class, Object.class) => false) dan juga menangani antarmuka dengan benar (mis. 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;
    }
}
pengguna2415587
sumber
3

Metode rekursif untuk memeriksa apakah a Class<?>adalah sub kelas dari Class<?>...

Versi perbaikan dari @To Kra 's jawabannya :

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);
    }
}
schuttek
sumber
3

//Warisan

    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'";
        }
    }

// Metode

    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;
        }
      }
    }

// Uji kodenya

    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));

//Hasil

    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
joseluisbz
sumber