如果我有两个接口,两者的目的完全不同,但是使用相同的方法签名,我如何在不强制编写为这两个接口服务的单个方法并编写一些复杂的逻辑的情况下使类实现两者在方法实现中,检查正在进行调用的对象类型并调用正确的代码?
在C#中,这被称为显式接口实现所克服。 Java中有没有相同的方法?
答案 0 :(得分:72)
不,没有办法在Java中的一个类中以两种不同的方式实现相同的方法。
这可能导致许多令人困惑的情况,这就是Java禁止它的原因。
interface ISomething {
void doSomething();
}
interface ISomething2 {
void doSomething();
}
class Impl implements ISomething, ISomething2 {
void doSomething() {} // There can only be one implementation of this method.
}
你可以做的是用两个类组成一个类,每个类实现不同的接口。然后那个类将具有两个接口的行为。
class CompositeClass {
ISomething class1;
ISomething2 class2;
void doSomething1(){class1.doSomething();}
void doSomething2(){class2.doSomething();}
}
答案 1 :(得分:13)
在Java中没有真正的方法可以解决这个问题。您可以使用内部类作为解决方法:
interface Alfa { void m(); }
interface Beta { void m(); }
class AlfaBeta implements Alfa {
private int value;
public void m() { ++value; } // Alfa.m()
public Beta asBeta() {
return new Beta(){
public void m() { --value; } // Beta.m()
};
}
}
虽然它不允许从AlfaBeta
到Beta
的强制转换,但是向下转换通常是邪恶的,如果可以预期Alfa
实例通常有Beta
}方面,由于某种原因(通常是优化是唯一有效的原因),您希望能够将其转换为Beta
,您可以创建Alfa
的子接口{{1}在它里面。
答案 2 :(得分:11)
如果您遇到此问题,很可能是因为您正在使用委托 继承。如果您需要为相同的基础数据模型提供两个不同的(虽然类似的)接口,那么您应该使用视图以便宜的方式使用其他接口提供对数据的访问。
为了给出后一种情况的具体示例,假设您要同时实现Collection
和MyCollection
(它不从Collection
继承而且具有不兼容的接口)。您可以使用相同的基础数据提供Collection getCollectionView()
和MyCollection getMyCollectionView()
函数,这些函数提供Collection
和MyCollection
的轻量级实现。
对于前一种情况......假设你真的想要一个整数数组和一个字符串数组。您应该拥有List<Integer>
类型的一个成员和List<String>
类型的另一个成员,而不是继承List<Integer>
和List<String>
,并引用这些成员,而不是尝试继承两者。即使你只需要一个整数列表,在这种情况下最好使用组合/委托而不是继承。
答案 3 :(得分:1)
“经典”Java问题也会影响我的Android开发......
原因似乎很简单:
你必须使用更多的框架/库,更容易失控的事情......
在我的情况下,我有一个继承自 android.app.Application 的 BootStrapperApp 类,
而同一个类也应该实现MVVM框架的 Platform 接口以便集成。
方法冲突发生在 getString() 方法上,该方法由两个接口公布,并且应该在不同的上下文中具有不同的实现。
解决方法(ugly..IMO)使用内部类来实现所有 Platform 方法,只是因为一个次要的方法签名冲突...在某些情况下,这种借用的方法甚至根本就没用过(但受影响的主要设计语义)
我倾向于同意C#式显式上下文/命名空间指示是有帮助的。
答案 4 :(得分:1)
我脑海中唯一的解决方案是使用引用对象来实现多个接口。
例如:假设您有2个接口来实现
public interface Framework1Interface {
void method(Object o);
}
和
public interface Framework2Interface {
void method(Object o);
}
你可以将它们包含在两个Facador对象中:
public class Facador1 implements Framework1Interface {
private final ObjectToUse reference;
public static Framework1Interface Create(ObjectToUse ref) {
return new Facador1(ref);
}
private Facador1(ObjectToUse refObject) {
this.reference = refObject;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Framework1Interface) {
return this == obj;
} else if (obj instanceof ObjectToUse) {
return reference == obj;
}
return super.equals(obj);
}
@Override
public void method(Object o) {
reference.methodForFrameWork1(o);
}
}
和
public class Facador2 implements Framework2Interface {
private final ObjectToUse reference;
public static Framework2Interface Create(ObjectToUse ref) {
return new Facador2(ref);
}
private Facador2(ObjectToUse refObject) {
this.reference = refObject;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Framework2Interface) {
return this == obj;
} else if (obj instanceof ObjectToUse) {
return reference == obj;
}
return super.equals(obj);
}
@Override
public void method(Object o) {
reference.methodForFrameWork2(o);
}
}
最后,你想要的课程应该是
public class ObjectToUse {
private Framework1Interface facFramework1Interface;
private Framework2Interface facFramework2Interface;
public ObjectToUse() {
}
public Framework1Interface getAsFramework1Interface() {
if (facFramework1Interface == null) {
facFramework1Interface = Facador1.Create(this);
}
return facFramework1Interface;
}
public Framework2Interface getAsFramework2Interface() {
if (facFramework2Interface == null) {
facFramework2Interface = Facador2.Create(this);
}
return facFramework2Interface;
}
public void methodForFrameWork1(Object o) {
}
public void methodForFrameWork2(Object o) {
}
}
您现在可以使用getAs *方法“公开”您的班级
答案 5 :(得分:0)
您可以使用适配器模式以使这些工作。为每个接口创建两个适配器并使用它。它应该解决问题。
答案 6 :(得分:-1)
当您完全控制所有相关代码并且可以预先实现此功能时,一切顺利。 现在假设你有一个现有的公共类在很多地方用了一个方法
public class MyClass{
private String name;
MyClass(String name){
this.name = name;
}
public String getName(){
return name;
}
}
现在你需要将它传递到现成的WizzBangProcessor,它需要类来实现WBPInterface ...它也有一个getName()方法,但是这个接口不是你的具体实现,而是希望方法返回名字一种Wizz Bang Processing。
在C#中,这将是一个小小的
public class MyClass : WBPInterface{
private String name;
String WBPInterface.getName(){
return "MyWizzBangProcessor";
}
MyClass(String name){
this.name = name;
}
public String getName(){
return name;
}
}
在Java中,您必须确定现有部署代码库中需要从一个接口转换到另一个接口的每个点。当然WizzBangProcessor公司应该使用getWizzBangProcessName(),但他们也是开发人员。在他们的上下文中getName很好。实际上,在Java之外,大多数其他基于OO的语言都支持这一点。 Java很少强制使用相同的方法NAME实现所有接口。
大多数其他语言都有一个编译器非常乐意接受一条指令说“此类中的此方法与此实现接口中此方法的签名匹配是它的实现”。毕竟定义接口的全部要点是允许从实现中抽象出定义。 (甚至不要让我开始使用Java中的接口中的默认方法,更不用说默认覆盖....因为当然,为公路车设计的每个组件都应该能够被撞到飞行的汽车而且只是工作 - 嘿它们都是汽车......我确信默认的功能是说你的卫星导航不会受到默认俯仰和滚动输入的影响,因为汽车只会偏航!