Tentukan apakah Kelas mengimplementasikan antarmuka di Java

92

Saya punya Classobjek. Saya ingin menentukan apakah tipe yang Classdiwakili objek mengimplementasikan antarmuka tertentu. Saya bertanya-tanya bagaimana ini bisa dicapai?

Saya memiliki kode berikut. Pada dasarnya apa yang dilakukannya adalah mendapatkan array dari semua kelas dalam paket yang ditentukan. Saya kemudian ingin melalui array dan menambahkan objek Kelas yang mengimplementasikan antarmuka ke peta saya. Masalahnya adalah isInstance()mengambil objek sebagai parameter. Saya tidak bisa membuat contoh antarmuka. Jadi saya agak bingung dengan ini. Ada ide?

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(clazz.isInstance(/*Some object*/)) //Need something in this if statement
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}
pengguna489041
sumber

Jawaban:

215

Anda harus menggunakan isAssignableFrom:

if (YourInterface.class.isAssignableFrom(clazz)) {
    ...
}
Flavio
sumber
Ini berfungsi jika proyeknya sama. Tetapi jika Anda menyalin kode antarmuka 1: 1, membuat proyek dan jar baru, lalu mencoba memuat jar itu sebagai plugin, panggilan akan mengembalikan false. Membandingkan dengan nama lalu "berhasil", seperti yang diposting Roddy. Tetapi saya tidak tahu bagaimana memeriksa ini dengan cara Java pada akhirnya memverifikasi kompatibilitasnya. Dengan nama adalah pendekatan yang kotor. Anda baik-baik saja, tentu saja, jika proyeknya sama. ................ MUNGKIN saya melakukan kesalahan: Saya membuat instance URLClassLoader untuk file plugin dan memuatnya seperti itu. Mungkin saya harus mencoba loader kelas yang berbeda.
Presiden Dreamspace
4
Anda mengalami masalah saat memuat kelas. Jika Anda memuat kelas yang sama dua kali dengan pemuat kelas yang berbeda, kedua Classinstance tersebut tidak akan kompatibel. Anda bisa melihat kesalahan seperti java.lang.ClassCastException: com.my.CustomClass cannot be cast to com.my.CustomClassatau sesuatu yang tidak bisa dijelaskan.
Flavio
Saya sekarang telah mencoba berbagai pendekatan, dan pada akhirnya, ternyata masalah utama yang saya hadapi adalah ini: Meskipun antarmuka di plugin dan proyek utama saya identik, mereka tidak berada di tempat yang sama, jadi namespace / alamat berbeda. Btw., Saya sekarang menggunakan: myClassLoader = new URLClassLoader(new URL[] { candidateFile.toURI().toURL() }, LoadedPlugin.class.getClassLoader());and classToLoad = Class.forName("com.blablabla.plugin.Main", true, myClassLoader);and instance = (MyIntf) classToLoad.newInstance();Works like a charm.
Presiden Dreamspace
17

Anda dapat menggunakan fungsi di bawah ini untuk mendapatkan semua antarmuka yang diimplementasikan

Class[] intfs = clazz.getInterfaces();
Ankur
sumber
10

Anda dapat menggunakan class.getInterfaces()dan kemudian memeriksa untuk melihat apakah kelas antarmuka ada di sana.

Class someInterface; // the interface you want to check for 
Class x; // 
Class[] interfaces = x.getInterfaces();

for (Class i : interfaces) {
    if (i.toString().equals(someInterface.toString()) {
        // if this is true, the class implements the interface you're looking for
    }
}
Roddy dari Kacang Beku
sumber
Pendekatan ini secara teknis akan berhasil, tetapi pendekatan yang jauh lebih sederhana dan lebih bersih adalah dengan menggunakan isAssignableFromseperti yang disebutkan Flavio.
jwj
Ya, itu benar, meskipun jawaban Anda telah dinaikkan lebih dari beberapa kali dan saya pikir akan berguna untuk menambahkan beberapa konteks. Meskipun menggunakan isAssignableFrommungkin lebih disukai, mungkin ada contoh di mana Anda perlu memindai daftar antarmuka yang diimplementasikan kelas dengan melihat namanya.
jwj
Ini sebenarnya tidak berfungsi, getInterfaces () hanya berfungsi jika kelas mengimplementasikan antarmuka secara langsung, jika superclass mengimplementasikan antarmuka, atau antarmuka super memperluasnya, antarmuka itu tidak akan dikembalikan oleh getInterfaces (). Anda perlu melintasi pohon semua kelas super dan antarmuka untuk mendapatkan semua antarmuka yang diimplementasikan kelas.
James Roper
Tapi itu bukan pertanyaannya.
Roddy of the Frozen Peas
1

Anda juga dapat menyetel instance dengan menambahkan ".class"

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(Interface.class.isAssignableFrom(clazz))
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}
Manu Navarro
sumber
2
Untuk siapapun yang melihat pendekatan ini, mohon pertimbangkan jawaban Flavio. Perhatikan bahwa kode dalam contoh ini melakukan beberapa hal yang mungkin tidak langsung masuk akal: ClassUtilsbukan bagian dari Java (ada di Guava atau Spring dan framework lain), istilah yang Interfacedigunakan di atas dimaksudkan untuk merujuk ke antarmuka tertentu yang sedang diuji ( yaitu, ini bukan kata kunci Java dalam konteks ini), dan tujuan dari retValtidak dijelaskan atau disebutkan di mana pun.
jwj