Bir Sınıfın Java'da bir arayüz uygulayıp uygulamadığını belirleme


92

Bir Classnesnem var. ClassNesnenin temsil ettiği türün belirli bir arabirimi uygulayıp uygulamadığını belirlemek istiyorum . Bunun nasıl başarılabileceğini merak ediyordum.

Takip koduna sahibim. Temel olarak yaptığı şey, belirli bir paketteki tüm sınıfların bir dizisini almaktır. Daha sonra diziye gitmek ve haritama bir arabirim uygulayan Sınıf nesnelerini eklemek istiyorum. Sorun, isInstance()bir nesneyi parametre olarak almasıdır. Bir arayüzü başlatamıyorum. Bu yüzden bu konuda bir kaybım var. Herhangi bir fikir?

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

Yanıtlar:


215

Kullanmalısınız isAssignableFrom:

if (YourInterface.class.isAssignableFrom(clazz)) {
    ...
}

Proje aynıysa bu işe yarar. Ancak arabirim kodunu 1: 1 kopyalarsanız, yeni bir proje ve jar oluşturun, ardından bu jar'i bir eklenti olarak yüklemeyi deneyin, çağrı yanlış olarak dönecektir. Roddy'nin yayınladığı gibi, isme göre karşılaştırma ve ardından "işler". Ancak Java'nın sonunda uyumluluğu doğrulaması gibi bunu nasıl kontrol edeceğimi bilmiyorum. Adına göre kirli bir yaklaşımdır. Tabii ki proje aynıysa sizinki iyidir. ................ MAYBE Yanlış yapıyorum: Eklenti dosyası için bir URLClassLoader örneği oluşturuyorum ve bu şekilde yüklüyorum. Belki farklı bir sınıf yükleyici denemeliyim.
Dreamspace Başkan

4
Sınıf yükleme sorunları yaşıyorsunuz. Aynı sınıfı farklı sınıf yükleyicilerle iki kez yüklerseniz, iki Classörnek uyumlu olmayacaktır. java.lang.ClassCastException: com.my.CustomClass cannot be cast to com.my.CustomClassBenzer hatalar veya benzer şekilde açıklanamayan bir şey görebilirsiniz .
Flavio

Şimdiye kadar çeşitli yaklaşımları denedim ve sonunda, karşılaştığım asıl problem şuydu: Eklentimdeki ve ana projemdeki arayüz aynıyken, aynı yerde değillerdi, dolayısıyla ad alanı / adres farklı biriydi. . Btw, şimdi kullanıyorum: myClassLoader = new URLClassLoader(new URL[] { candidateFile.toURI().toURL() }, LoadedPlugin.class.getClassLoader());ve classToLoad = Class.forName("com.blablabla.plugin.Main", true, myClassLoader);ve instance = (MyIntf) classToLoad.newInstance();bir cazibe gibi çalışır.
Dreamspace Başkan

17

uygulanan tüm arayüzleri almak için aşağıdaki işlevi kullanabilirsiniz

Class[] intfs = clazz.getInterfaces();

10

class.getInterfaces()Arayüz sınıfının orada olup olmadığını kontrol edebilir ve kullanabilirsiniz .

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

Bu yaklaşım teknik olarak işe yarayacak, ancak çok daha basit ve daha temiz olan yaklaşım, isAssignableFromFlavio'nun bahsettiği gibi kullanmaktır .
jwj

Evet, bu doğru, ancak cevabınız birkaç kereden fazla yükseltilmiş olsa da, biraz bağlam eklemenin faydalı olacağını düşündüm. Kullanmak isAssignableFrombüyük olasılıkla tercih edilirken , bir sınıfın uyguladığı arabirimlerin listesini adlara bakarak taramanız gereken durumlar olabilir.
jwj

Bu aslında işe yaramaz, getInterfaces () yalnızca sınıf arabirimi doğrudan uygularsa, arabirimi bir üst sınıf uygularsa veya bir süper arabirim onu ​​genişletirse çalışır, bu arabirim getInterfaces () tarafından döndürülmez. Sınıfın uyguladığı tüm arabirimleri elde etmek için tüm süper sınıfların ve arabirimlerin ağacında gezinmeniz gerekir.
James Roper

Yine de soru bu değildi.
Roddy of the Frozen Peas

1

Örneği ".class" ekleyerek de ayarlayabilirsiniz.

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(Interface.class.isAssignableFrom(clazz))
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}

2
Bu yaklaşıma bakan biri için lütfen Flavio'nun cevabını düşünün. Bu örnekteki kodun hemen bir anlam ifade etmeyebilecek birkaç şeyi yaptığını unutmayın: ClassUtilsJava'nın bir parçası değildir (Guava veya Spring ve diğer çerçevelerde), Interfaceyukarıda kullanılan terim , test edilmekte olan belirli bir arayüze atıfta bulunmak içindir ( yani, bu bağlamda bir Java anahtar kelimesi değildir) ve amacı retValhiçbir yerde açıklanmamaktadır veya bahsedilmemektedir.
jwj
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.