![](/img/trans.png)
[英]Is it possible to have an interface method defined with a generic return type and a concrete implementation define the return type?
[英]How can an interface include a method that references the concrete implementation type of the interface in its signature or return type?
假设我正在设计类似以下界面的内容:
public interface MyInterface{
public MyInterface method1();
public void method2(MyInterface mi);
}
但是,需要注意的是, method1
的返回类型和method2
的参数与具体实现匹配,而不仅仅是MyInterface
。 也就是说,如果我有MyInterfaceImpl
实现MyInterface
,它需要具备以下条件:
public class MyInterfaceImpl implements MyInterface{
@Override
public MyInterfaceImpl method1(){...}
@Override
public void method2(MyInterfaceImpl mi){...}
}
如上所述, method1
不会导致任何编译错误,但是不能保证在所有实现中返回类型都匹配。 当然method2
甚至不会编译,因为签名与接口不匹配。
一种候选解决方案是在泛型中使用自引用或递归范围:
public interface MyInterface<T extends MyInterface<T>>{
public T method1();
public void method2(T mi);
}
public class MyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
@Override
public MyInterfaceImpl method1();
@Override
public void method2(MyInterfaceImpl mi);
}
这将使我得到我想要的东西,但有一个例外:其他实现可能传递了错误的泛型类型(没有力T
匹配具体类型)。 因此,可能其他人可以实现以下目标:
public class NotMyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
@Override
public MyInterfaceImpl method1();
@Override
public void method2(MyInterfaceImpl mi);
}
即使NotMyInterfaceImpl
应该实现MyInterface<NotMyInterfaceImpl>
也可以很好地编译。*这使我认为我还需要其他东西。
*请注意,我不认为我要违反LSP; 我可以将返回类型/参数设置为NotMyInterfaceImpl
子类。
所以我不知道这样做的干净方法。 这使我相信我可能会过多地关注界面中的实现细节,但对我而言似乎并非如此。 有什么方法可以做我描述的事情,还是我在某种不属于该接口的接口中闻到这种气味?
这是Comparable
接口所面临的确切情况(其compareTo
方法要采用与调用它的对象相同类型的参数)。 那怎么办呢? 它被简单地定义为Comparable<T>
。 这个想法是,一个实现类“应该”将Comparable
与自身实现为参数(允许它与自身“比较”)。 但这不是强制性的(因为没有办法这样做)。
是的,正如您所指出的,这将允许任何类使用任何其他类的参数来实现Comparable
: class Foo implements Comparable<Bar>
,其中Foo
和Bar
彼此无关。 但是,这并不是真正的问题。
所有需要Comparable
对象的方法和类(排序,最大值等)都具有以下通用类型约束<T extends Comparable<? super T>>
<T extends Comparable<? super T>>
。 这样可以确保T类型的对象与其自身具有可比性。 这样,它是完全类型安全的。 因此,实施不是在Comparable接口的声明中进行的,而是在使用它的地方进行的。
(我注意到您使用<T extends MyInterface<T>>
而Comparable
仅使用<T>
。尽管<T extends MyInterface<T>>
会排除类型参数未实现MyInterface
,但不会排除其中类型参数确实实现了MyInterface
,但与类有所不同,因此排除某些情况的意义何在呢?如果您采用Comparable
的方式将其限制在使用它们的地方,那么无论如何它都是类型安全的,所以没有意义添加更多限制。)
我相信这是不可能的。 据我所知,根本没有办法在泛型框架中引用对象的实现类,就我所知,也没有任何方法可以用纯泛型构造笼子,这种笼子能够约束实现类以匹配类型参数。
我可以建议的最有用的方法是使用自引用参数,然后始终从工厂方法中获取实现实例,如下所示:
public <T extends MyInterface<T>> T newInstance();
骆驼穿过针眼要比NotMyInterfaceImpl
实例通过该返回类型NotMyInterfaceImpl
。 因此,尽管麻烦制造者可能编写的类与您的总体规划不符,但他们无法从工厂退还它们。 除非NotMyInterfaceImpl
扩展了MyInterfaceImpl
; 但是从某种意义上讲,它也将是MyInterfaceImpl
,所以也许是犹太洁食?
编辑:该想法的一个稍微有用的版本是始终在适当限制的持有人周围传递接口的实现实例,例如:
class Holder<T extends MyInterface<T>> {
public final T value;
}
如果有人给您Holder<Q>
,那么您知道Q
必须是绑定到其自身的MyInterface
的版本,这就是您所追求的。
您尝试执行的操作是不合法的,因为您尝试缩小已实现类型的参数,而这“没有道理” 。 您正在尝试使用“ covariant”参数 ,并且仅允许使用协变返回类型(甚至是逻辑,并且仅Java 5支持 )。
我的意思是,如果可以使用协变参数类型,则可以执行以下操作:
MyInterface instance = new MyInterfaceImpl();
然后,通过接口支持但MyInterfaceImpl类不支持的另一个实现在“实例”上调用该方法:
instance.method2(new MyInterfaceImpl_2());
Java无法将MyInterfaceImpl_2
转换为MyInterfaceImpl
,因此它阻止您在编译时这样做。
您可以做的是使用“ contravariant”参数扩展参数,这很合理。 有关此的更多详细信息,请检查以下分析器:
我能想到的唯一解决方法是在运行时解决问题,这是说:
public class MyInterfaceImpl implements MyInterface{
@Override
public void method2(MyInterface mi){
realMethod((MyInterfaceImpl) mi);
}
public void realMethod(MyInterfaceImpl) {...}
}
但是,您当然可以得到ClassCast异常。
返回接口的目的是使该方法不关心返回对象的实际实现。 在您的情况下,您实际上希望将类型强制为该接口的特定子实现。
若要应用您上面描述的约束,恕我直言,设计可能应该是基类而不是接口。 这使您可以控制实现,例如顶层流程,并将低级策略留给子类来实现:
class MyBaseImpl {
public final void fixedFlow() {
MyBaseImpl obj = method1();
obj.method2(this);
}
protected abstract MyBaseImpl method1();
....
}
必须有其他使它变得有趣的方法。 也许您有充分的理由要这样做...
希望这可以帮助!
这是你想要的?
public interface MyInterface {
static abstract class MyInterfaceImpl implements MyInterface {
@Override
public abstract MyInterfaceImpl method1();
@Override
public abstract void method2(MyInterfaceImpl mi);
}
MyInterfaceImpl method1();
void method2(MyInterfaceImpl mi);
}
您甚至可以实现方法1或2,而不用抽象它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.