6

public class myClass implements A, BA と B の両方に method public int doSomething();が含まれているクラスがA.doSomethingありますが、 とは異なることを行うようにインターフェイスによって指定されていますB.doSomething

Two interfaces with same method signature implemented in Java classを読みましたが、メソッドは同じことを行うためにオーバーライドされているため、実際には問題に対処していませんが、上で述べたように、私の質問はそれらがいつ指定されるかについてですさまざまなことを行うためのインターフェース。

たとえば、A.doSomething()は を返すはず0で、 whileB.doSomething()は例外をスローするはずであり、いずれかに違反すると、それらをパラメーターとして受け取るはずのメソッドで問題が発生するとします。

Javaでこれを行う方法はありますか? もしそうなら、実際にどのようにそれを行うでしょうか?

4

3 に答える 3

5

JLSに従って (これはあなたが望むものと同様のケースであり、正確ではないかもしれません)

interface Fish { int getNumberOfScales(); }
interface StringBass { double getNumberOfScales(); }
class Bass implements Fish, StringBass {
    // This declaration cannot be correct, no matter what type is used.
    public ??? getNumberOfScales() { return 91; }
}

署名と戻り値の型がインターフェイス Fish とインターフェイス StringBass で宣言された両方のメソッドの署名と戻り値の型と互換性があるという名前のメソッドを宣言することは不可能です。これは、クラスが同じ署名と異なるプリミティブな戻り値の型を持つ複数のメソッドを持つことができないためです (§8.4)。 .getNumberOfScales

プロキシ (または) メソッド シグネチャを追加して設計を変更しない限り、期待どおりの動作をすることはできません。

于 2012-12-05T18:59:29.523 に答える
1

Proxyこれを行うためにインスタンスを使用できる場合があります。詳細については、この質問を参照してくださいProxy(特に、回答の2番目の部分)。

作成したInvocationHandlerは、メソッドの呼び出しに使用されているインターフェイスを確認し、オブジェクト内の適切なメソッドに委任します。実装は次のようになります。

public class MyClass {
    // Note that we aren't implementing the interfaces anymore

    public int doSomethingForA() {
        return 0;
    }

    public int doSomethingForB() {
        throw new IllegalArgumentException();
    }
}

次に、InvocationHandler:

public class MyClassInvocationHandler implements InvocationHandler {

    private MyClass target;

    public MyClassInvocationHandler(MyClass target) {
        this.target = target;
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        try {
            if (method.getDeclaringClass().equals(InterfaceA.class))
                return MyClass.getMethod("doSomethingForA").invoke(target, args);
            else if (method.getDeclaringClass().equals(InterfaceB.class))
                return MyClass.getMethod("doSomethingForB").invoke(target, args);
            else
                throw new UnsupportedOperationException("Unsupported interface: " + method.getDeclaringClass());
        } catch (NoSuchMethodException ex) {
            throw new UnsupportedOperationException("Method not found", ex);
        } catch (IllegalAccessException ex) {
            throw new UnsupportedOperationException("Method was not public", ex);
        } catch (InvocationTargetException ex) {
            // May throw a NullPointerException if there is no target exception
            throw ex.getTargetException();
        }
    }
}

次に、プロキシを作成するために、両方のインターフェイスを渡します。

Proxy.newProxyInstance(null, new Class<?>[] { InterfaceA.class, InterfaceB.class }, new MyClassInvocationHandler(mc));

これでうまくいくと思います。どちらかのインターフェイスを使用して呼び出すと、次のようになります。

MyClass mc = new MyClass();
Object proxy = Proxy.newProxyInstance(null, new Class<?>[] { InterfaceA.class, InterfaceB.class }, new MyClassInvocationHandler(mc));
InterfaceA a = (InterfaceA) proxy;
a.doSomething();
InterfaceB b = (InterfaceB) proxy;
b.doSomething();

次に、異なる宣言クラスを持つオブジェクトを渡す必要があります。Methodこれがどのように機能するかはわかりませんが、これはテストする必要があります。

于 2012-12-05T19:33:46.257 に答える
0

メソッドをオーバーロードする場合にのみ可能です(異なる戻り値の型)

public interface IA {
int doSomething();
}

public interface IB {
void doSomething(String value) throws Exception;
}

public class B  implements IB, IA{
    @Override
    public void doSomething(String value) throws Exception {
        throw new Exception(value);
    }

    @Override
    public int doSomething() {
        return 0;
    }
}
于 2012-12-05T19:46:49.287 に答える