2012-12-05 50 views
6

我有一些类public class myClass implements A, B其中A和B都包含一个方法public int doSomething();,但A.doSomething由接口指定做一些不同于B.doSomething两个接口指定具有相同签名的方法,而是规定为具有不同的行为?

我已阅读Two interfaces with same method signature implemented in Java class,但这并没有真正解决我的问题,因为方法被重写做同样的事情,但正如我上面所说,我的问题是关于何时在接口中指定它们以做不同的东西。

例如,假设A.doSomething()应该返回0,而B.doSomething()应该抛出一个异常,并违反了,都应该把他们作为参数方法中的任何一个沃尔德造成问题。

有没有办法在Java中做到这一点?如果是这样,一个人会怎么做呢?

+0

你有没有其他的办法,而不是更改签名之一。在同一个类中不能有两个具有相同签名的方法。 –

+0

在.NET中,您可以显式地实现接口成员,以便它们显示为私有的,除非实例被转换为特定的接口类型。所以你可以明确地实现两个实现。 Java是否有类似的构造? – jrummell

+0

@jrummell不,接口*的方法必须声明为public。另外,即使访问器不同,*和即使一个是静态声明的,另一个是非静态的*,但具有完全相同签名的两个方法(返回类型,名称和参数/参数顺序都是相同的)会给你编译器错误 – Brian

回答

1

您可能可以使用Proxy实例执行此操作。对Proxy信息请参见this question(特别是第二部分答案。)

,你会写检查,看看哪一个接口被用来调用该方法,并委托给你的对象内部的相应方法的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对象用不同的声明类。我不确定它是如何工作的,所以这需要进行测试。

+0

**免责声明:**这是*真* hacky,你应该只在绝对必要的时候这么做,也就是说你不能改变任何一个接口或创建两个不同的实现,数据限制。 – Brian

4

按照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; } 
} 

这是不可能申报命名getNumberOfScales的方法,其签名和返回类型是与两者兼容在Fish接口和StringBass接口中声明的方法,因为一个类不能有多个具有相同签名和不同基元返回类型(§8.4)的方法。

除非通过添加代理(或)方法签名来更改设计,否则无法执行您期望的操作。

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; 
    } 
} 
相关问题