Określ, czy klasa implementuje interfejs w języku Java

92

Mam Classprzedmiot. Chcę ustalić, czy typ, który Classreprezentuje obiekt, implementuje określony interfejs. Zastanawiałem się, jak można to osiągnąć?

Mam następujący kod. Zasadniczo pobiera tablicę wszystkich klas w określonym pakiecie. Następnie chcę przejść przez tablicę i dodać obiekty Class, które implementują interfejs do mojej mapy. Problem polega na tym, że isInstance()przyjmuje obiekt jako parametr. Nie mogę utworzyć instancji interfejsu. Więc jestem z tym trochę zagubiony. Jakieś pomysły?

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);
    }
}
user489041
źródło

Odpowiedzi:

215

Powinieneś użyć isAssignableFrom:

if (YourInterface.class.isAssignableFrom(clazz)) {
    ...
}
Flavio
źródło
Działa to, jeśli projekt jest taki sam. Ale jeśli skopiujesz kod interfejsu 1: 1, stworzysz nowy projekt i jar, a następnie spróbujesz załadować ten jar jako wtyczkę, wywołanie zwróci false. Porównując według nazwy, a następnie „prac”, jak napisał Roddy. Ale nie mam pojęcia, jak to sprawdzić w sposób, w jaki Java ostatecznie weryfikuje zgodność. Z nazwy to brudne podejście. Twój jest w porządku, oczywiście, jeśli projekt jest taki sam. ................ MOŻE robię to źle: tworzę instancję URLClassLoader dla pliku wtyczki i ładuję ją w ten sposób. Może powinienem wypróbować program ładujący innej klasy.
Prezydent Dreamspace
4
Masz problemy z ładowaniem zajęć. Jeśli załadujesz tę samą klasę dwukrotnie za pomocą różnych programów ładujących klasy, te dwie Classinstancje nie będą kompatybilne. Możesz zobaczyć błędy, takie jak java.lang.ClassCastException: com.my.CustomClass cannot be cast to com.my.CustomClasslub coś podobnie niewytłumaczalnego.
Flavio,
Do tej pory wypróbowałem różne podejścia i ostatecznie okazało się, że główny problem jaki miałem był taki: podczas gdy interfejs w mojej wtyczce i głównym projekcie były identyczne, to nie były w tym samym miejscu, więc przestrzeń nazw / adres był inny. . Btw, jestem teraz przy użyciu: myClassLoader = new URLClassLoader(new URL[] { candidateFile.toURI().toURL() }, LoadedPlugin.class.getClassLoader());a classToLoad = Class.forName("com.blablabla.plugin.Main", true, myClassLoader);i instance = (MyIntf) classToLoad.newInstance();działa jak czar.
Prezydent Dreamspace
17

możesz użyć poniższej funkcji, aby uzyskać wszystkie zaimplementowane interfejsy

Class[] intfs = clazz.getInterfaces();
Ankur
źródło
10

Możesz użyć, class.getInterfaces()a następnie sprawdzić, czy klasa interfejsu jest tam.

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 z Frozen Peas
źródło
Podejście to sprawdzi się technicznie, ale o wiele prostszym i czystszym podejściem jest użycie, isAssignableFromjak wspomina Flavio.
jwj
Tak, to prawda, chociaż twoja odpowiedź była głosowana więcej niż kilka razy i pomyślałem, że warto dodać jakiś kontekst. Chociaż używanie isAssignableFromjest prawdopodobnie preferowane, mogą wystąpić przypadki, w których trzeba będzie przejrzeć listę interfejsów implementowanych przez klasę, patrząc na nazwy.
jwj
W rzeczywistości to nie działa, getInterfaces () działa tylko wtedy, gdy klasa implementuje interfejs bezpośrednio, jeśli nadklasa implementuje interfejs lub superinterfejs rozszerza go, ten interfejs nie zostanie zwrócony przez getInterfaces (). Musisz przejść przez drzewo wszystkich superklas i interfejsów, aby uzyskać wszystkie interfejsy implementowane przez klasę.
James Roper,
To nie było jednak pytanie.
Roddy of the Frozen Peas
1

Możesz też ustawić instancję, dodając „.class”

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(Interface.class.isAssignableFrom(clazz))
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}
Manu Navarro
źródło
2
Każdy, kto patrzy na to podejście, powinien rozważyć odpowiedź Flavio. Zwróć uwagę, że kod w tym przykładzie robi kilka rzeczy, które mogą nie mieć natychmiastowego sensu: ClassUtilsnie jest częścią Javy (jest w Guava, Spring i innych frameworkach), termin Interfaceużyty powyżej ma odnosić się do konkretnego testowanego interfejsu ( tj. nie jest to słowo kluczowe Java w tym kontekście), a cel funkcji retValnie jest nigdzie wyjaśniony ani wymieniony.
jwj