Java泛型:接口方法接收实现类的类型参数

31
在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) {
       ...
    }

}    




编辑:

好的,我会尝试用另一种方式来描述我想要实现的目标。 我想要有几个类,这些类有一个方法,接受该类类型的参数。 所以除了上面提到的A类之外,假设还有另一个B类看起来像这样:

public class B implements MyInterface {

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

}

类A和B共同拥有一个名为“method”的方法,该方法接收一个类型为该类本身的参数。

在我的项目中,我想实现以下内容。我正在编写一个小游戏,并希望实现某种形式的碰撞检测。基本上,我想通过一些“智能”的多态调用来完成这个任务。

我定义了一个名为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,因为播放器会接收碰撞并处理它们。这应该以一种通用的方式完成,因此例如我有方框和圆形,现在Player实现了ICollisionReceiver<Box>和ICollisionReceiver<Circle>,因此我有了两种方法。

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

并且

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

在我的盒子和圆形类中,我可以注册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() 方法。

现在重点是,我希望确保框和圆两个类都只使用自己的类型来实现ICollisionChecker接口。

我可以通过像这样做来显式地实现:

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

但这对我来说并不令人满意...很抱歉发了这么长的帖子,希望现在清楚了。

3
“public <T extends MyInterface> void method(T object);” 不是一个选择,因为说实话,我不理解你想要达到什么目的。 - Zhedar
3个回答

39

在Java中,您想要的是不可能的,并且也没有用处。

因此,这应该是不允许的:

为什么呢?它有什么作用呢?泛型不是用来施加任意限制的。泛型只有在可以证明强制转换始终安全的情况下才能消除必需的强制转换。

只要 public class A implements MyInterface<B> 是类型安全的,就没有必要施加任意限制来禁止它。

您应该只需将接口定义为

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

那就这样吧,你为什么在意呢?这会引起什么问题吗?


2
哈,第一句话之后我就知道是你了。总是试图将CRTP赶出城外 :) - Paul Bellora
1
是的,这确实是一种限制,可能不是泛型的一般意图,但它也提供了某种类型安全性,因为它确保只有一个类型处理该类型本身的冲突。因此,我认为/希望这是可能的。尽管如此,非常感谢您的回答。 - krinklesaurus

6

好的,这至少是可能的:

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

从上面的代码可以看出,泛型声明看起来有点像无限递归,如果 Java 不使用类型擦除技术,我相信这样写代码将会变得非常困难。但是值得庆幸的是,所有的泛型都被编译器处理成了 Object 类型,所以你可以这样使用它们。

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!

4
作为注脚,我认为这完全是无意义的,我不鼓励任何人真正使用它。 - Esko
谢谢,但我仍然可以这样做:public class ImplBlubb implements SelfImplementer<Impl>,所以ImplBlubb将使用Impl实现接口。我的意思是,只有ImplBlubb才能实现与ImplBlubb的接口,而Impl只能使用Impl实现接口... - krinklesaurus
这不是 OP 想要的。你仍然可以拥有 public class SomeOtherImpl implements SelfImplementer<Impl> - newacct

-1
你想要做的可能是这样的:

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

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

希望这有所帮助!


您还需要将接口声明指定为 public interface MyInterface<T>,以便Java知道T是什么。 - Michael
1
感谢您的回应。不幸的是,这仍然允许ClassImplementingMyInterface成为一个不是A的类。 - krinklesaurus
实际上这不是必要的 - 我为方法声明了泛型,而不是类! - thruun
1
我不确定我理解为什么你想这样做。限制MyInterface只接受继承自A的东西会破坏接口的目的。这违反了“面向接口编程而非实现”原则,因为它将接口绑定到该接口的具体实现。 - Michael

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接