6

我有一些类public class myClass implements A, B,其中 A 和 B 都包含一个方法 public int doSomething();,但A.doSomething由接口指定做一些不同于B.doSomething.

我已经阅读了在 Java 类中实现了具有相同方法签名的两个接口,但这并不能真正解决我的问题,因为这些方法被覆盖以执行相同的操作,但正如我上面所说,我的问题是关于它们何时在做不同事情的接口。

例如,假设A.doSomething()应该返回0,而B.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 和接口StringBassgetNumberOfScales中声明的方法兼容的命名方法,因为一个类不能有多个具有相同签名和不同原始返回类型的方法(第 8.4 节) .

除非您通过添加代理(或)方法签名来更改您的设计,否则不可能做到您所期望的。

于 2012-12-05T18:59:29.523 回答
1

您也许可以使用Proxy实例来执行此操作。有关(特别是答案的第二部分)的信息,请参阅此问题。Proxy

您编写的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 回答