【问题标题】:Java Generics: interface method that receives type argument of implementing classJava Generics:接收实现类的类型参数的接口方法
【发布时间】:2013-02-02 19:15:12
【问题描述】:

在Java中,是否可以定义一个接口,该接口具有一个接收实现类参数的方法?

界面:

public interface MyInterface {
   public <T is/extends of the type of the implementing class> void method(T object);
}

类:

public class A implements MyInterface {

    public void method(A object) {
       ...
    }

}

我要避免的是,一个类可以用另一个像它自己的类来实现 MyInterface。

所以这是不允许的:

public class A implements MyInterface<B> {

    public void method(B object) {
       ...
    }

}    





编辑:

好的,我尝试用另一种方式描述我想要实现的目标。我希望有几个类具有接受该类类型的 arg 的方法。因此,除了上面的 A 类之外,我们可以说还有另一个 B 类,看起来像这样:

public class B implements MyInterface {

    public void method(B object) {
       ...
    }

}

展位类 A 和 B 的共同点是一个称为“方法”的方法,它接收类本身类型的 arg。

在我的项目中,我想实现以下目标。我在写一个小游戏,想实现某种碰撞检测。基本上我想通过做一些“智能”多态调用来做到这一点。

我定义了一个接口 ICollisionReceiver,如下所示:

public interface ICollisionReceiver<T extends IShape> extends IShape {

    public boolean collides(T t);

}

我定义了另一个这样的接口:

public interface ICollisionChecker<T extends ICollisionChecker<T>> extends IShape {

    public void addCollisionReceiver(ICollisionReceiver<T> receiver);

    public void removeCollisionReceiver(ICollisionReceiver<T> receiver);

}

例如,现在我的播放器在接收碰撞并处理它们时实现接口 ICollisionReceiver。这应该以通用方式完成,例如我有盒子和圆圈,现在播放器实现 ICollisionReceiver 和 ICollisionReceiver 所以我有两种方法

@Override
public boolean collides(final Box b) {        
    ...
    return false;
}

@Override
public boolean collides(final Circle c) {        
    ...
    return false;
}

在我的 box 和 circle 类中,我可以注册 ICollisionReceivers,然后在更新方法中执行以下操作:

    boolean conti = true;
    int i=0;
    while(conti && i<collisionReceivers.size()) {
        final ICollisionReceiver<Bonus> rec = collisionReceivers.get(i);               
        if(this.collidesWith(rec)) {
            conti = rec.collides(this);
        }            
        ++i;
    }

这主要是检查此框是否与某个接收器发生碰撞,然后调用接收器的 collides() 方法。

现在的重点是,我要确保 box 和 circle 类都仅使用自己的类型实现 ICollisionChecker 接口。

我明确地可以通过这样做来做到这一点

public class Bonus extends AnimatedSprite implements ICollisionChecker<Bonus>...

但这对我来说不是很满意......

抱歉,这篇文章太长了,我希望这能让你清楚。

【问题讨论】:

  • public &lt;T extends MyInterface&gt; void method(T object); 不是一个选项吗?因为如果我说实话,我不明白你想要实现什么。

标签: java generics types


【解决方案1】:

你想要的东西在 Java 中是不可能的,而且没用。

所以这是不允许的:

为什么不呢?那有什么用?泛型不是为你做出任意限制的。泛型仅对消除您原本需要的强制转换有用,因为它可以证明强制转换始终是安全的。

只要public class A implements MyInterface&lt;B&gt; 是类型安全的,就没有必要进行任意限制来禁止它。

你应该简单地将你的界面定义为

public interface MyInterface<T> {
   public void method(T object);
}

你可以定义你的类

public class A implements MyInterface<A> {
    public void method(A object) {
    }
}

如果其他人定义了一个类

public class B implements MyInterface<A> {
    public void method(A object) {
    }
}

那就这样吧。你为什么在乎?会导致什么问题?

【讨论】:

  • 哈,第一句话我就知道是你。总是试图在城外运行 CRTP :)
  • 是的,这是一个限制,一般来说可能不是泛型的意图,但它也提供了某种类型的安全性,因为它可以确保一种类型只处理这种类型本身的冲突。因此,我认为/希望这是可能的。不过,非常感谢您的回答。
【解决方案2】:

嗯,这至少是可能的:

public interface SelfImplementer<T extends SelfImplementer<T>> {
    void method(T self);
}

如您所见,Generic 声明看起来有点像无限递归,我相当确定如果 Java 没有 有类型擦除,那么它会 - 谢天谢地(?)所有泛型实际上是 Objects 在编译器处理它们之后,所以你可以这样做

public class Impl implements SelfImplementer<Impl> {
    @Override
    public void method(Impl self) {
        System.out.println("Hello!");
    }
}

正如预期的那样,这个

public static void main(String[] args) {
    Impl impl = new Impl();
    impl.method(impl);
}

打印出来

Hello!

【讨论】:

  • 作为脚注,我认为这完全是荒谬的,我不会鼓励任何人实际使用它。
  • 谢谢,但我仍然可以这样做:公共类 ImplBlubb 实现 SelfImplementer,因此 ImplBlubb 将使用 Impl 实现接口。我想要的是,ImplBlubb 只能用 ImplBlubb 实现接口,而 Impl 只能用 Impl 实现接口...
  • 这不符合 OP 的要求。你仍然可以拥有public class SomeOtherImpl implements SelfImplementer&lt;Impl&gt;
【解决方案3】:

你想做的大概是这样的:

public interface MyInterface <T extends A> {
    public void method(T object) {
        ...
    }
}

public class A implements MyInterface<A_or_class_extending_A>
{ ... }

我希望这会有所帮助!

【讨论】:

  • 您还需要将接口声明指定为public interface MyInterface&lt;T&gt;,以便Java 知道T 是什么。
  • 感谢您的回复。不幸的是,这仍然允许 ClassImplementingMyInterface 成为不是 A 的类。
  • 其实这不是必需的——我为方法声明了泛型,而不是为类声明!
  • 我不确定我是否理解您为什么要这样做。将MyInterface 限制为只接受扩展A 的东西会破坏接口的目的。通过将接口绑定到该接口的具体实现,这违反了“程序到接口而不是实现”的原则。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-16
  • 1970-01-01
相关资源
最近更新 更多