Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/343.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 接口如何包含在其签名或返回类型中引用接口的具体实现类型的方法?_Java_Generics_Interface_Return Type_Method Signature - Fatal编程技术网

Java 接口如何包含在其签名或返回类型中引用接口的具体实现类型的方法?

Java 接口如何包含在其签名或返回类型中引用接口的具体实现类型的方法?,java,generics,interface,return-type,method-signature,Java,Generics,Interface,Return Type,Method Signature,假设我正在设计如下界面: public interface MyInterface{ public MyInterface method1(); public void method2(MyInterface mi); } 但是,需要注意的是method1的返回类型和method2的参数与具体实现匹配,而不仅仅是MyInterface。也就是说,如果我有实现MyInterface的MyInterfaceImpl,它需要具备以下功能: public class MyInterfaceIm

假设我正在设计如下界面:

public interface MyInterface{
  public MyInterface method1();
  public void method2(MyInterface mi);
}
但是,需要注意的是
method1
的返回类型和
method2
的参数与具体实现匹配,而不仅仅是
MyInterface
。也就是说,如果我有实现
MyInterface
MyInterfaceImpl
,它需要具备以下功能:

public class MyInterfaceImpl implements MyInterface{
  @Override
  public MyInterfaceImpl method1(){...}

  @Override
  public void method2(MyInterfaceImpl mi){...}
}
public class NotMyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
  @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);
}
尽管
NotMyInterfaceImpl
应该实现
MyInterface
*,这让我觉得我还需要其他东西,但编译起来还是不错的

*请注意,我不认为我试图违反LSP;我同意返回类型/参数是
notmyinterfaceeimpl
的子类


所以我不知道一个干净的方法来做这件事。这让我相信,我可能过于关注接口中的实现细节,但在我看来并非如此。有没有办法做到我描述的那种事情,或者这是某种气味,我把一些东西放在了一个不属于那里的界面上?

我认为这是不可能做到的。根本没有办法在泛型框架中引用对象的实现类,就我所知,也没有办法用纯泛型构造一个框架,该框架能够约束实现类以匹配类型参数

我能建议的最有用的事情是使用自引用参数,然后始终从工厂方法获取实现实例,如下所示:

public <T extends MyInterface<T>> T newInstance();

如果有人给你一个
Holder
,那么你就知道
Q
必须是绑定到自身的
MyInterface
版本,这就是你所追求的。

你试图做的是不合法的,因为你试图缩小实现类型的参数,而这“没有意义”。您尝试使用“协变”参数,并且只允许协变返回类型(甚至逻辑,并且仅允许)

我的意思是,如果可以使用协变参数类型,您可以执行以下操作:

MyInterface instance = new MyInterfaceImpl();
然后,使用接口支持但MyInterfaceImpl类不支持的另一个实现在“实例”上调用该方法:

instance.method2(new MyInterfaceImpl_2());
Java无法将
MyInterfaceImpl_2
转换为
MyInterfaceImpl
,因此它阻止您在编译时这样做

您可以做的是拓宽参数,使用“逆变”参数,这将是逻辑。有关此问题的更多详细信息,请查看此答案:

我能想到的唯一解决办法是在运行时解决问题,我的意思是,做如下事情:

public class MyInterfaceImpl implements MyInterface{
  @Override
  public void method2(MyInterface mi){
        realMethod((MyInterfaceImpl) mi);
  }
  public void realMethod(MyInterfaceImpl) {...}
}

当然,您可能会得到ClassCast异常。

返回接口的要点是,该方法不关心返回对象的实际实现。在您的例子中,您实际上希望将该类型指定为该接口的特定子实现

要应用上面描述的约束,IMHO设计可能应该是基类而不是接口。这允许您控制实现,例如顶级流,并将低级策略留给子类来实现:

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,而不是将其抽象化。

这正是
Comparable
接口所面临的情况(其
compareTo
方法希望采用与其调用的对象相同类型的参数)。那么它有什么作用呢?它的简单定义是
可比较的
。其思想是,一个实现类“应该”实现
compariable
,并将其自身作为参数(允许它“与”自身进行比较);但这并不是强制的(因为没有办法)

是的,正如您所指出的,这将允许任何类使用任何其他类的参数实现
Comparable
class Foo实现Comparable
,其中
Foo
Bar
彼此没有关系。然而,这并不是一个真正的问题


所有需要
compariable
对象的方法和类(排序、最大值等)都有以下泛型类型约束,但是,通常试图创建一个需要知道其底层实现是什么的接口,这表明对接口的用途缺乏基本的理解。你可能需要从你的设计中退一步。如果你读了我的最后一段,我有点担心我可能违反了我应该对接口做的事情。
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);

}