Определите, реализует ли класс интерфейс в Java

92

У меня есть Classобъект. Я хочу определить, Classреализует ли тип, который представляет объект, определенный интерфейс. Мне было интересно, как этого можно достичь?

У меня есть следующий код. По сути, он получает массив всех классов в указанном пакете. Затем я хочу пройтись по массиву и добавить объекты класса, реализующие интерфейс на мою карту. Проблема в том, isInstance()что в качестве параметра используется объект. Я не могу создать интерфейс. Так что я немного растерялся. Любые идеи?

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
источник

Ответы:

215

Вам следует использовать isAssignableFrom:

if (YourInterface.class.isAssignableFrom(clazz)) {
    ...
}
Флавио
источник
Это работает, если проект такой же. Но если вы скопируете код интерфейса 1: 1, создадите новый проект и jar, а затем попытаетесь загрузить этот jar как плагин, вызов вернет false. Сравнение по названию то "работает", как и отправил Родди. Но я понятия не имею, как это проверить так, как Java в конечном итоге проверяет совместимость. По названию это грязный подход. Твой, конечно, нормально, если проект такой же. ................ ВОЗМОЖНО, я делаю это неправильно: я создаю экземпляр URLClassLoader для файла плагина и загружаю его вот так. Может мне стоит попробовать другой загрузчик классов.
Президент Dreamspace
4
У вас проблемы с загрузкой класса. Если вы загрузите один и тот же класс дважды с разными загрузчиками классов, два Classэкземпляра не будут совместимы. Вы могли увидеть ошибки вроде java.lang.ClassCastException: com.my.CustomClass cannot be cast to com.my.CustomClassили что-то подобное необъяснимое.
Flavio
К настоящему времени я пробовал различные подходы, и в конце концов выяснилось, что основная проблема, с которой я столкнулся, заключалась в следующем: хотя интерфейс в моем плагине и основном проекте были идентичны, они не находились в одном месте, поэтому пространство имен / адрес был другим. Кстати, сейчас пользуюсь: myClassLoader = new URLClassLoader(new URL[] { candidateFile.toURI().toURL() }, LoadedPlugin.class.getClassLoader());и classToLoad = Class.forName("com.blablabla.plugin.Main", true, myClassLoader);и instance = (MyIntf) classToLoad.newInstance();работает как шарм.
Президент Dreamspace
17

вы можете использовать приведенную ниже функцию, чтобы получить все реализованные интерфейсы

Class[] intfs = clazz.getInterfaces();
Анкур
источник
10

Вы можете использовать, class.getInterfaces()а затем проверить, есть ли там класс интерфейса.

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
    }
}
Родди из замороженного горошка
источник
Технически этот подход будет работать, но, isAssignableFromкак упоминает Флавио, гораздо проще и чище .
jwj
Да, это правда, хотя за ваш ответ проголосовали несколько раз, и я подумал, что было бы полезно добавить некоторый контекст. Хотя использование isAssignableFrom, вероятно, предпочтительнее, могут быть случаи, когда вам нужно просмотреть список интерфейсов, реализуемых классом, просмотрев их имена.
jwj
На самом деле это не работает, getInterfaces () работает только в том случае, если класс реализует интерфейс напрямую, если суперкласс реализует интерфейс или супер-интерфейс расширяет его, этот интерфейс не будет возвращен getInterfaces (). Вам необходимо пройти по дереву всех суперклассов и интерфейсов, чтобы получить все интерфейсы, которые реализует класс.
Джеймс Ропер
Но вопрос был не в этом.
Родди из Frozen Peas
1

Вы также можете установить экземпляр, добавляющий ".class"

Class[] classes = ClassUtils.getClasses(handlersPackage);
for(Class clazz : classes)
{
    if(Interface.class.isAssignableFrom(clazz))
    {
        retVal.put(clazz.getSimpleName(), clazz);
    }
}
Ману Наварро
источник
2
Для тех, кто смотрит на этот подход, обратите внимание на ответ Флавио. Обратите внимание, что код в этом примере выполняет несколько вещей, которые могут не иметь непосредственного смысла: ClassUtilsне является частью Java (он находится в Guava, Spring и других фреймворках), термин, Interfaceиспользуемый выше, предназначен для обозначения конкретного тестируемого интерфейса ( т.е. в данном контексте это не ключевое слово Java), и retValнигде не объясняется и не упоминается его назначение.
jwj