Визначте, чи клас реалізує інтерфейс у Java


91

У мене є Classпредмет. Я хочу визначити, чи тип, який представляє 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);
    }
}

Відповіді:


214

Ви повинні використовувати 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або щось подібне до незрозумілих.
Флавіо,

Я вже випробував різні підходи, і врешті-решт, виявилося, що головна проблема у мене була така: Хоча інтерфейс у моєму плагіні та основному проекті були однаковими, вони знаходились не в одному місці, тому простір імен / адреса був інший. До речі, зараз я використовую: 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 (). Вам потрібно пройти дерево всіх супер класів та інтерфейсів, щоб отримати всі інтерфейси, які реалізує клас.
James Roper

Це було не питання.
Родді з замороженого гороху

1

Ви також можете встановити екземпляр, додавши ".class"

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

2
Для тих, хто дивиться на цей підхід, розгляньте відповідь Флавіо. Зверніть увагу, що код у цьому прикладі робить кілька речей, які можуть не мати безпосереднього сенсу: ClassUtilsвін не є частиною Java (це в Гуаві чи Spring та інших фреймворках), термін, Interfaceяк використаний вище, позначає певний тестований інтерфейс ( тобто, це не ключове слово Java у цьому контексті), і мета цього retValніде не пояснюється і не згадується.
jwj
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.