クラスがJavaでインターフェースを実装するかどうかを判別する


92

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

回答:


215

使用する必要がありますisAssignableFrom

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

これは、プロジェクトが同じ場合に機能します。ただし、インターフェイスコード1:1をコピーして、新しいプロジェクトとjarを作成し、そのjarをプラグインとしてロードしようとすると、呼び出しはfalseを返します。Roddyが投稿したように、名前で比較すると「機能」します。しかし、Javaが最終的に互換性を検証する方法でこれを確認する方法がわかりません。名前では汚いアプローチです。もちろん、プロジェクトが同じであれば、あなたは大丈夫です。................間違っている可能性があります:プラグインファイルのURLClassLoaderインスタンスを作成し、そのようにロードします。たぶん、別のクラスローダーを試してみる必要があります。
Dreamspace President 2018

4
クラスの読み込みに問題があります。同じクラスを異なるクラスローダーで2回ロードすると、2つの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、Flavioが言及しているように、はるかに単純でクリーンなアプローチを使用することです。
jwj 2017

はい、それは本当ですが、あなたの答えは数回以上賛成されており、いくつかのコンテキストを追加すると便利だと思いました。使用isAssignableFromすることをお勧めしますが、名前を調べて、クラスが実装するインターフェイスのリストをスキャンする必要がある場合があります。
jwj 2017

これは実際には機能しません。getInterfaces()は、クラスがインターフェイスを直接実装する場合、スーパークラスがインターフェイスを実装する場合、またはスーパーインターフェイスがインターフェイスを拡張する場合にのみ機能し、そのインターフェイスはgetInterfaces()によって返されません。クラスが実装するすべてのインターフェイスを取得するには、すべてのスーパークラスとインターフェイスのツリーをトラバースする必要があります。
ジェームズローパー

しかし、それは問題ではありませんでした。
冷凍エンドウ豆のロディ

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 2017
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.