如何使用在 java 中引用 self-type 的抽象方法创建接口
How to create an interface with abstract methods that reference self-type in java
我确定此问题已被回答 100 次,但我不确定要搜索什么。
我想创建一个带有抽象方法的接口,该接口强制执行实现它的 class 的 self-type 参数。
哎呀,真是一口。
例如,我有一个名为 Collider 的接口,带有一个名为 isColliding 的方法。我有一个名为 Player 的 class 实现了 Collider。在我的用例中,只有 objects 的 Collider sub-type 需要检查它们是否相互碰撞。我希望 Player 实现方法 isColliding,但我希望函数原型被强制执行为 isColliding(Player p),而不是 isColliding(Collider c)
通过将 Collider 声明为
,我已经设法实现了我认为的 work-around
public interface Collider<T extends Collider<T>> {
public abstract boolean isColliding(T other);
}
但是当我声明实现对撞机的 class 时,class 原型看起来像这样
public class Player implements Collider<Player>
这看起来很难看,而且不一定像我想要的那样 type-safe。似乎应该有一种方法可以暗示 。我的目标是让 child class 的覆盖函数原型看起来像这样
public boolean isColliding(Player other)
提前致谢!
编辑:
提供更多背景信息:
我有一个名为 Collision 的单例 class,它注册了我的 objects 可能会相互碰撞的对象。在 Collision 内部,我有一个 Hashmap 声明为
HashMap<Class, ArrayList<Collider>> colliders
这是我的数据结构,用于存储可能相互碰撞的objects。它们被 class 映射,因为我的设计只要求每个 class 检查它是否与自身发生碰撞。 Collision 有自己的 isColliding 函数,可以从实现 Collider 的 objects 中调用。看起来像这样
public <T extends Collider> boolean isColliding(T c) throws ColliderNotPopulatedException {
ArrayList<T> cList = (ArrayList<T>)colliders.get(c.getClass());
if (cList == null) {
throw new ColliderNotPopulatedException();
}
for (T otherC : cList) {
if (c != otherC && c.isColliding(otherC)) {
return true;
}
}
return false;
}
我尝试在此方法中调用 isColliding 时出现 NoSuchMethod 错误,我怀疑这是因为未实现 self-typeness。我应该 re-think 我的设计吗?是否有模式可以使它更清洁?
编辑 2:
我设法克服了在调用 isColliding 时将 'otherC' 转换为类型 (T) 的错误。看来这个实现对我有用。感谢大家的帮助!
我认为最好的方法是您展示的方法
然而,另一种方法可能是在 Collider 接口中定义它
public boolean isColliding(Object object);
然后这样实现方法
class Player implements Collider{
public boolean isColliding(Object object){
if( object instanceof Player ){
// some stuff
return true;
}
return false;
}
}
我更喜欢像你一样使用模板,所以方法有固定的类型。
这个设计看起来很奇怪:用一个 T
类型声明 Collider
就足够了:
interface Collider<T> {
boolean isColliding(T other);
}
在这种情况下,实现 classes 检查与相同类型对象的碰撞:
class Person implements Collider<Person> {
@Override
public boolean isColliding(Person otherPerson) {
...
}
}
例如,这与 Comparable
界面非常相似。
声明 <T extends Collider<T>>
更强大并确保实现 class 只能将 Collider 子类型指定为通用类型:
class Person implements Collider<Person> - this will work
class Person implements Collider<String> - this will not work
还是不要求使用同类型 - class Person1 implements Collider<Person2>
- 合法
也许我误会了,但我假设每种类型的对象的比较方法都是相同的,因为您不想覆盖每个 class 的方法,而真正重要的是只有比较相同类型的对象。然后根据 Andrea 的回答,您也许可以使用:
class Collider{
public boolean isColliding(Object o){
if (this.getClass() == o.getClass()){
//Do some stuff
return true;
}
return false;
}
}
不过我认为您的通用答案还可以,毕竟这是 java 用于 Comparable 的模式。
您似乎在尝试创建某种游戏或游戏引擎,对吧?在这种情况下,我还猜测在某些时候您不仅希望检测人与人之间的碰撞,还希望检测其他事物(例如人、怪物、车辆等)之间的碰撞。
您可能需要重新考虑一下您的设计,而不是进入自我类型。
首先,我建议您将所有可能发生碰撞的对象设为一个公共类型的子类,该类型公开可用于检测碰撞的属性(可能是位置、多边形等)。
public interface GameObejct {
int getProperty1();
int getProperty2();
}
public class Person implements GameObejct {
@Override
public int getProperty1() {
return 0;
}
@Override
public int getProperty2() {
return 0;
}
}
public class Monster implements GameObejct{
@Override
public int getProperty1() {
return 0;
}
@Override
public int getProperty2() {
return 0;
}
}
碰撞检测逻辑不属于物体(人、怪物等),但在 program.The 物体的另一部分,它自己不需要知道它可以与某物发生碰撞。
由于您表达了使用不同碰撞检测方法的愿望,您可以使用碰撞检测策略并创建您可以使用的各种实例。
public interface CollidingDetectionPolicy <T extends GameObejct> {
boolean objectsColliding(T object1,T object2);
}
public class SimpleCollisionDetector implements CollidingDetectionPolicy<GameObejct> {
@Override
public boolean objectsColliding(GameObejct object1, GameObejct object2) {
// detect collision using a simple method...
return false;
}
}
public class ComplexCollisionDetector implements CollidingDetectionPolicy<GameObejct> {
@Override
public boolean objectsColliding(GameObejct object1, GameObejct object2) {
// detect collision using some other more complex method
return false;
}
}
游戏的主引擎应该在适当的时候检查碰撞。
public class GameEngine {
public void detectCollisions() {
/// ...
/// ...
// need to know if there is some collision
// get all the objects on screen and the current collision detection policy (see note)
List<GameObejct> currentlyVisibleObjects = getObjectsOnScreen();
CollidingDetectionPolicy collisionDetector = getCollisionDetectionLogic();
// naive implementation . don't traverse your list this way!Think about complexity!
for (int i = 0; i < currentlyVisibleObjects.size() - 1; i++) {
GameObejct object1 = currentlyVisibleObjects.get(i);
for (int j = i + 1; j < currentlyVisibleObjects.size(); j++) {
GameObejct object2 = currentlyVisibleObjects.get(j);
if (collisionDetector.objectsColliding(object1, object2)) {
// object colliding ...do something
}
}
}
}
public List<GameObejct> getObjectsOnScreen () {
... // return the list of game objects
}
public CollidingDetectionPolicy getCollisionDetectionLogic() {
... /// return the detection implementation
}
}
注意:我不认为对象本身提供检测策略是明智的,因为在 2 个对象提供不同策略的情况下,比较语义会有点奇怪,如下例所示:
让我们假设对象本身可以使用方法
为我们提供其首选检测策略
public CollidingDetectionPolicy getDetectionPolicy();
我们必须检查这两个对象
Person p = ...;
Monster m = ..;
然后
p.getDetectionPolicy().objectsColliding(p, m)
结果可能与
不同
m.getDetectionPolicy().objectsColliding(p, m)
至少可以说这很奇怪。
界面Comparable
可以作为指南。正如 AdamSkywalker 在他的回答中提到的那样,
public interface Collider<T>
够用了。绑定在这里对您没有任何好处。
在任何方法或 class 中概括对撞机类型的地方,您可以使用边界
<T extends Collider<? super T>>
确保该类型可以检查与自身的冲突。
对于您的 Map
,通常无法在 Java 中声明将 Class
映射到 [=37= 的元素的 Map
变量] 以类型检查的方式(不管你是否限制了 classes 允许与否),因为 Map
的方法具有仅与整个类型参数相关的参数类型Map
,因此 Map
.
中的所有元素必须相同
但是,您可以编写一个包装器 class,其 API 强制执行此关系,例如,
class ClassToColliderList {
public <T extends Collider<? extends T>> void put(Class<T> clazz, List<T> list);
public <T extends Collider<? extends T>> List<T> get(Class<T> clazz);
}
这样的 class 仍然必须在内部存储某种类型的变量,例如 Map<Class<?>, List<?>>
并在内部进行未经检查的转换,但这都包含在 [=37 的私有实现细节中=],可以检查以保证它是安全的。
我确定此问题已被回答 100 次,但我不确定要搜索什么。 我想创建一个带有抽象方法的接口,该接口强制执行实现它的 class 的 self-type 参数。
哎呀,真是一口。
例如,我有一个名为 Collider 的接口,带有一个名为 isColliding 的方法。我有一个名为 Player 的 class 实现了 Collider。在我的用例中,只有 objects 的 Collider sub-type 需要检查它们是否相互碰撞。我希望 Player 实现方法 isColliding,但我希望函数原型被强制执行为 isColliding(Player p),而不是 isColliding(Collider c)
通过将 Collider 声明为
,我已经设法实现了我认为的 work-aroundpublic interface Collider<T extends Collider<T>> {
public abstract boolean isColliding(T other);
}
但是当我声明实现对撞机的 class 时,class 原型看起来像这样
public class Player implements Collider<Player>
这看起来很难看,而且不一定像我想要的那样 type-safe。似乎应该有一种方法可以暗示
public boolean isColliding(Player other)
提前致谢!
编辑:
提供更多背景信息:
我有一个名为 Collision 的单例 class,它注册了我的 objects 可能会相互碰撞的对象。在 Collision 内部,我有一个 Hashmap 声明为
HashMap<Class, ArrayList<Collider>> colliders
这是我的数据结构,用于存储可能相互碰撞的objects。它们被 class 映射,因为我的设计只要求每个 class 检查它是否与自身发生碰撞。 Collision 有自己的 isColliding 函数,可以从实现 Collider 的 objects 中调用。看起来像这样
public <T extends Collider> boolean isColliding(T c) throws ColliderNotPopulatedException {
ArrayList<T> cList = (ArrayList<T>)colliders.get(c.getClass());
if (cList == null) {
throw new ColliderNotPopulatedException();
}
for (T otherC : cList) {
if (c != otherC && c.isColliding(otherC)) {
return true;
}
}
return false;
}
我尝试在此方法中调用 isColliding 时出现 NoSuchMethod 错误,我怀疑这是因为未实现 self-typeness。我应该 re-think 我的设计吗?是否有模式可以使它更清洁?
编辑 2:
我设法克服了在调用 isColliding 时将 'otherC' 转换为类型 (T) 的错误。看来这个实现对我有用。感谢大家的帮助!
我认为最好的方法是您展示的方法
然而,另一种方法可能是在 Collider 接口中定义它
public boolean isColliding(Object object);
然后这样实现方法
class Player implements Collider{
public boolean isColliding(Object object){
if( object instanceof Player ){
// some stuff
return true;
}
return false;
}
}
我更喜欢像你一样使用模板,所以方法有固定的类型。
这个设计看起来很奇怪:用一个 T
类型声明 Collider
就足够了:
interface Collider<T> {
boolean isColliding(T other);
}
在这种情况下,实现 classes 检查与相同类型对象的碰撞:
class Person implements Collider<Person> {
@Override
public boolean isColliding(Person otherPerson) {
...
}
}
例如,这与 Comparable
界面非常相似。
声明 <T extends Collider<T>>
更强大并确保实现 class 只能将 Collider 子类型指定为通用类型:
class Person implements Collider<Person> - this will work
class Person implements Collider<String> - this will not work
还是不要求使用同类型 - class Person1 implements Collider<Person2>
- 合法
也许我误会了,但我假设每种类型的对象的比较方法都是相同的,因为您不想覆盖每个 class 的方法,而真正重要的是只有比较相同类型的对象。然后根据 Andrea 的回答,您也许可以使用:
class Collider{
public boolean isColliding(Object o){
if (this.getClass() == o.getClass()){
//Do some stuff
return true;
}
return false;
}
}
不过我认为您的通用答案还可以,毕竟这是 java 用于 Comparable 的模式。
您似乎在尝试创建某种游戏或游戏引擎,对吧?在这种情况下,我还猜测在某些时候您不仅希望检测人与人之间的碰撞,还希望检测其他事物(例如人、怪物、车辆等)之间的碰撞。
您可能需要重新考虑一下您的设计,而不是进入自我类型。
首先,我建议您将所有可能发生碰撞的对象设为一个公共类型的子类,该类型公开可用于检测碰撞的属性(可能是位置、多边形等)。
public interface GameObejct {
int getProperty1();
int getProperty2();
}
public class Person implements GameObejct {
@Override
public int getProperty1() {
return 0;
}
@Override
public int getProperty2() {
return 0;
}
}
public class Monster implements GameObejct{
@Override
public int getProperty1() {
return 0;
}
@Override
public int getProperty2() {
return 0;
}
}
碰撞检测逻辑不属于物体(人、怪物等),但在 program.The 物体的另一部分,它自己不需要知道它可以与某物发生碰撞。
由于您表达了使用不同碰撞检测方法的愿望,您可以使用碰撞检测策略并创建您可以使用的各种实例。
public interface CollidingDetectionPolicy <T extends GameObejct> {
boolean objectsColliding(T object1,T object2);
}
public class SimpleCollisionDetector implements CollidingDetectionPolicy<GameObejct> {
@Override
public boolean objectsColliding(GameObejct object1, GameObejct object2) {
// detect collision using a simple method...
return false;
}
}
public class ComplexCollisionDetector implements CollidingDetectionPolicy<GameObejct> {
@Override
public boolean objectsColliding(GameObejct object1, GameObejct object2) {
// detect collision using some other more complex method
return false;
}
}
游戏的主引擎应该在适当的时候检查碰撞。
public class GameEngine {
public void detectCollisions() {
/// ...
/// ...
// need to know if there is some collision
// get all the objects on screen and the current collision detection policy (see note)
List<GameObejct> currentlyVisibleObjects = getObjectsOnScreen();
CollidingDetectionPolicy collisionDetector = getCollisionDetectionLogic();
// naive implementation . don't traverse your list this way!Think about complexity!
for (int i = 0; i < currentlyVisibleObjects.size() - 1; i++) {
GameObejct object1 = currentlyVisibleObjects.get(i);
for (int j = i + 1; j < currentlyVisibleObjects.size(); j++) {
GameObejct object2 = currentlyVisibleObjects.get(j);
if (collisionDetector.objectsColliding(object1, object2)) {
// object colliding ...do something
}
}
}
}
public List<GameObejct> getObjectsOnScreen () {
... // return the list of game objects
}
public CollidingDetectionPolicy getCollisionDetectionLogic() {
... /// return the detection implementation
}
}
注意:我不认为对象本身提供检测策略是明智的,因为在 2 个对象提供不同策略的情况下,比较语义会有点奇怪,如下例所示:
让我们假设对象本身可以使用方法
为我们提供其首选检测策略public CollidingDetectionPolicy getDetectionPolicy();
我们必须检查这两个对象
Person p = ...;
Monster m = ..;
然后
p.getDetectionPolicy().objectsColliding(p, m)
结果可能与
不同m.getDetectionPolicy().objectsColliding(p, m)
至少可以说这很奇怪。
界面Comparable
可以作为指南。正如 AdamSkywalker 在他的回答中提到的那样,
public interface Collider<T>
够用了。绑定在这里对您没有任何好处。
在任何方法或 class 中概括对撞机类型的地方,您可以使用边界
<T extends Collider<? super T>>
确保该类型可以检查与自身的冲突。
对于您的 Map
,通常无法在 Java 中声明将 Class
映射到 [=37= 的元素的 Map
变量] 以类型检查的方式(不管你是否限制了 classes 允许与否),因为 Map
的方法具有仅与整个类型参数相关的参数类型Map
,因此 Map
.
但是,您可以编写一个包装器 class,其 API 强制执行此关系,例如,
class ClassToColliderList {
public <T extends Collider<? extends T>> void put(Class<T> clazz, List<T> list);
public <T extends Collider<? extends T>> List<T> get(Class<T> clazz);
}
这样的 class 仍然必须在内部存储某种类型的变量,例如 Map<Class<?>, List<?>>
并在内部进行未经检查的转换,但这都包含在 [=37 的私有实现细节中=],可以检查以保证它是安全的。