简体   繁体   English

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

[英]How can an interface include a method that references the concrete implementation type of the interface in its signature or return type?

Suppose I am designing something like the following interface: 假设我正在设计类似以下界面的内容:

public interface MyInterface{
  public MyInterface method1();
  public void method2(MyInterface mi);
}

However, there is the caveat that the return type for method1 and the parameter for method2 match the concrete implementation and not just MyInterface . 但是,需要注意的是, method1的返回类型和method2的参数与具体实现匹配,而不仅仅是MyInterface That is, if I have MyInterfaceImpl that implements MyInterface , it needs to have the following: 也就是说,如果我有MyInterfaceImpl实现MyInterface ,它需要具备以下条件:

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

  @Override
  public void method2(MyInterfaceImpl mi){...}
}

As written above, method1 won't cause any compile errors, but there is nothing guaranteeing that the return type matches in all implementations. 如上所述, method1不会导致任何编译错误,但是不能保证在所有实现中返回类型都匹配。 Of course method2 won't even compile because the signature does not match the interface. 当然method2甚至不会编译,因为签名与接口不匹配。

One candidate solution is to use self-referential or recursive bounds in generics: 一种候选解决方案是在泛型中使用自引用或递归范围:

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);
}

This would get me what I want with one exception: other implementations might pass the wrong generic type (nothing forces T to match the concrete type). 这将使我得到我想要的东西,但有一个例外:其他实现可能传递了错误的泛型类型(没有力T匹配具体类型)。 So potentially someone else could implement the following: 因此,可能其他人可以实现以下目标:

public class NotMyInterfaceImpl implements MyInterface<MyInterfaceImpl>{
  @Override
  public MyInterfaceImpl method1();

  @Override
  public void method2(MyInterfaceImpl mi);
} 

That would compile just fine even though NotMyInterfaceImpl should implement MyInterface<NotMyInterfaceImpl> .* That makes me think I need something else. 即使NotMyInterfaceImpl 应该实现MyInterface<NotMyInterfaceImpl>也可以很好地编译。*这使我认为我还需要其他东西。

*Note that I don't think I'm trying to violate LSP; *请注意,我不认为我要违反LSP; I'm OK with the return type/parameter being subclasses of NotMyInterfaceImpl . 我可以将返回类型/参数设置为NotMyInterfaceImpl子类。

So I don't know of a clean way to do this. 所以我不知道这样做的干净方法。 That leads me to believe that I might be focusing too much on implementation details in the interface, but it doesn't seem that way to me. 这使我相信我可能会过多地关注界面中的实现细节,但对我而言似乎并非如此。 Is there any way to do the type of thing I described, or is this some kind of smell that I'm putting something in an interface that doesn't belong there? 有什么方法可以做我描述的事情,还是我在某种不属于该接口的接口中闻到这种气味?

This is the exact situation faced by the Comparable interface (its compareTo method wants to take an argument the same type as the object it is called on). 这是Comparable接口所面临的确切情况(其compareTo方法要采用与调用它的对象相同类型的参数)。 So what does it do? 那怎么办呢? It's simply defined as Comparable<T> . 它被简单地定义为Comparable<T> The idea is that an implementing class "should" implement Comparable with itself as the parameter (allowing it to "compare to" itself); 这个想法是,一个实现类“应该”将Comparable与自身实现为参数(允许它与自身“比较”)。 but this is not enforced (since there is no way to do it). 但这不是强制性的(因为没有办法这样做)。

Yes, as you noted, this will allow any class to implement Comparable with a parameter of any other class: class Foo implements Comparable<Bar> where Foo and Bar have no relation to each other. 是的,正如您所指出的,这将允许任何类使用任何其他类的参数来实现Comparableclass Foo implements Comparable<Bar> ,其中FooBar彼此无关。 However, this is not really a problem. 但是,这并不是真正的问题。

All the methods and classes (sorting, maximum, etc.) that require Comparable objects have the following generic type constraint <T extends Comparable<? super T>> 所有需要Comparable对象的方法和类(排序,最大值等)都具有以下通用类型约束<T extends Comparable<? super T>> <T extends Comparable<? super T>> . <T extends Comparable<? super T>> This ensures that objects of type T are comparable with themselves. 这样可以确保T类型的对象与其自身具有可比性。 That way, it is completely type-safe. 这样,它是完全类型安全的。 So the enforcement is not made in the declaration of the Comparable interface, but in the places that use it. 因此,实施不是在Comparable接口的声明中进行的,而是在使用它的地方进行的。

(I notice that you use <T extends MyInterface<T>> while Comparable uses simply <T> . Although <T extends MyInterface<T>> will exclude cases where the type parameter does not implement MyInterface , it will not exclude cases where the type parameter does implement MyInterface , but is different than the class. So what's the point of half-excluding some cases? If you adopt Comparable 's way of restricting it where they are used, it's type-safe anyway, so there is no point in adding more restrictions.) (我注意到您使用<T extends MyInterface<T>>Comparable仅使用<T> 。尽管<T extends MyInterface<T>>会排除类型参数未实现MyInterface ,但不会排除其中类型参数确实实现了MyInterface ,但与类有所不同,因此排除某些情况的意义何在呢?如果您采用Comparable的方式将其限制在使用它们的地方,那么无论如何它都是类型安全的,所以没有意义添加更多限制。)

I believe that this cannot be done. 我相信这是不可能的。 There is simply no way to refer to an object's implementation class in the framework of generics, nor, as far as i know, any way to construct a cage out of pure generics which is capable of constraining the implementation class to match a type parameter. 据我所知,根本没有办法在泛型框架中引用对象的实现类,就我所知,也没有任何方法可以用纯泛型构造笼子,这种笼子能够约束实现类以匹配类型参数。

The most useful thing i can suggest is using a self-referential parameter, and then always acquiring instances of implementations from factory methods which look like: 我可以建议的最有用的方法是使用自引用参数,然后始终从工厂方法中获取实现实例,如下所示:

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

It is easier for a camel to pass through the eye of a needle than for an instance of NotMyInterfaceImpl to pass through that return type. 骆驼穿过针眼要比NotMyInterfaceImpl实例通过该返回类型NotMyInterfaceImpl So, although troublemakers could write classes which do not conform to your masterplan, they couldn't return them from factories. 因此,尽管麻烦制造者可能编写的类与您的总体规划不符,但他们无法从工厂退还它们。 Unless NotMyInterfaceImpl extended MyInterfaceImpl ; 除非NotMyInterfaceImpl扩展了MyInterfaceImpl ; but then, in a sense, it would also be a MyInterfaceImpl , so perhaps that would be kosher? 但是从某种意义上讲,它也将是MyInterfaceImpl ,所以也许是犹太洁食?

EDIT: A slightly more useful version of that idea is to always pass instances of implementations of the interface around in a suitably restrictive holder, like: 编辑:该想法的一个稍微有用的版本是始终在适当限制的持有人周围传递接口的实现实例,例如:

class Holder<T extends MyInterface<T>> {
    public final T value;
}

If someone gives you a Holder<Q> , then you know that Q must be a version of MyInterface bound to itself, which is what you're after. 如果有人给您Holder<Q> ,那么您知道Q必须是绑定到其自身的MyInterface的版本,这就是您所追求的。

What you are trying to do is not legal because you are trying to narrow the parameter of the implemented type, and this "does not make sense" . 您尝试执行的操作是不合法的,因为您尝试缩小已实现类型的参数,而这“没有道理” You are tryint to use "covariant" parameters , and only covariant return types are allowed (and even logic, and only supported from Java 5 ). 您正在尝试使用“ covariant”参数 ,并且仅允许使用变返回类型(甚至是逻辑,并且仅Java 5支持 )。

I mean, if it was possible to use covariant parameter types, you could do things like: 我的意思是,如果可以使用协变参数类型,则可以执行以下操作:

MyInterface instance = new MyInterfaceImpl();

And then, invoke on "instance" the method with another implementation supported by the interface but not supported by the MyInterfaceImpl class this way: 然后,通过接口支持但MyInterfaceImpl类不支持的另一个实现在“实例”上调用该方法:

instance.method2(new MyInterfaceImpl_2());

Java cannot convert MyInterfaceImpl_2 to MyInterfaceImpl , so it prevents you from doing so at compilation time. Java无法将MyInterfaceImpl_2转换为MyInterfaceImpl ,因此它阻止您在编译时这样做。

What you could do is to widen the parameter, using "contravariant" parameter, which would be logic. 您可以做的是使用“ contravariant”参数扩展参数,这很合理。 For more detail on this, check this anser: 有关此的更多详细信息,请检查以下分析器:

Demonstrate covariance and contravariance in Java? 演示Java中的协方差和矛盾?

The only workaround that I can think of, is to solve the problem at runtime, I mean, doing something like this: 我能想到的唯一解决方法是在运行时解决问题,这是说:

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

But you could get ClassCast exception, of course. 但是,您当然可以得到ClassCast异常。

The point of returning the interface is such that the method does not care the actual implementation of the returned object. 返回接口的目的是使该方法不关心返回对象的实际实现。 In your case you actually want to mandate the type to be a particular sub-implementation of that interface. 在您的情况下,您实际上希望将类型强制为该接口的特定子实现。

To apply the constraints that you described above, IMHO the design should probably be a base class instead of an interface. 若要应用您上面描述的约束,恕我直言,设计可能应该是基类而不是接口。 This allows you to control the implementation, for example a top-level flow, and leave low-level strategy to sub-classes to implement: 这使您可以控制实现,例如顶层流程,并将低级策略留给子类来实现:

class MyBaseImpl {
    public final void fixedFlow() {
        MyBaseImpl obj = method1();
        obj.method2(this);
    }
    protected abstract MyBaseImpl method1();
    ....
}

There has to be other methods to make it interesting...; 必须有其他使它变得有趣的方法。 perhaps you have good reasons to want to do this... 也许您有充分的理由要这样做...

Hope this helps! 希望这可以帮助!

Is this what you are looking for? 这是你想要的?

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);

}

And you could even implement method 1 or 2 instead of making them abstract. 您甚至可以实现方法1或2,而不用抽象它们。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 是否可以使用泛型返回类型定义接口方法,并且具体实现定义返回类型? - Is it possible to have an interface method defined with a generic return type and a concrete implementation define the return type? 与需要签名中实现类型的参数的方法进行接口 - Interface with a method that requires parameter of implementation type in signature 当接口方法的泛型返回使用 Java 中的具体类型实现时,如何避免“未检查覆盖”警告? - How can I avoid an "Unchecked overriding" warning when interface method's generic return is implemented with a concrete type in Java? 如何在实现通用接口时返回具体类型 - How to return a concrete type when implementing a generic interface 如何实现一个将返回一个具体类型的枚举的方法签名? - How To Implement A Method Signature That Will Return a Concrete Type of an Enum? Java 中方法的签名是否包括其返回类型? - Does a method's signature in Java include its return type? 如何在Clojure中使用具体类型参数实现接口? - How to implement an interface with concrete type parameters in Clojure? 如何获得具体类型的通用接口 - How to get concrete type of a generic interface 如何返回类型接口 - How to return type Interface 如何在方法接口中返回通用类型 - How to return generic type in a method interface
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM