Определите, реализует ли класс интерфейс в 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);
    }
}

Ответы:


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
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.