Java中的泛型类(安全键入)相互依赖
我想创建一个抽象集合类(称为Space)和一个 抽象元素类(称为Atom)。两者的实例必须相互了解(精确键入)。 这就是问题所在Java中的泛型类(安全键入)相互依赖,java,generics,types,Java,Generics,Types,我想创建一个抽象集合类(称为Space)和一个 抽象元素类(称为Atom)。两者的实例必须相互了解(精确键入)。 这就是问题所在 abstract class Space<A extends Atom>{ // ... } abstract class Atom<S extends Space>{ // ... } 抽象类空间{ // ... } 抽象类原子{ // ... } 不好: “扩展原子”指任何原子,但不是强类型原子 “S扩展空间”指任何空间,但不
abstract class Space<A extends Atom>{
// ...
}
abstract class Atom<S extends Space>{
// ...
}
抽象类空间{
// ...
}
抽象类原子{
// ...
}
不好:
“扩展原子”指任何原子,但不是强类型原子
“S扩展空间”指任何空间,但不是强类型空间
我也无法通过以下尝试达到完全的类型安全:
abstract class Space<A extends Atom<? extends Space>>
abstract class Atom<S extends Space<? extends Atom>>
abstract class Space<S, A extends Atom<S extends Space<A>>>
abstract class Atom<A, S extends Space<A extends Atom<S>>>
and so on ...
抽象类空间让Java中的参数化类型了解其实际具体类型的唯一方法是在构造时传入类型参数:
public Foo<T>(class<T> klass, // other parameters
public Foo(类klass,//其他参数
元答案是,循环类型依赖关系是有问题的,这表明需要重新审视您的设计。通常,更好的解决方案是在第三种类型上具有层次依赖关系:
public class SomeAtom extends Atom<Something>
public class SomeSpace extends Space<Something>
公共类SomeAtom扩展了Atom
公共类空间扩展了空间
元答案是,“类型安全性”有其局限性,无论使用何种语言:让Java中的参数化类型了解其实际具体类型的唯一方法是在构造时传入类型参数:
public Foo<T>(class<T> klass, // other parameters
public Foo(类klass,//其他参数
元答案是,循环类型依赖关系是有问题的,这表明需要重新审视您的设计。通常,更好的解决方案是在第三种类型上具有层次依赖关系:
public class SomeAtom extends Atom<Something>
public class SomeSpace extends Space<Something>
公共类SomeAtom扩展了Atom
公共类空间扩展了空间
元答案是,“类型安全性”有其局限性,无论使用何种语言:抽象类空间{}
抽象类Atom{}
或者,我想,如果你愿意的话
abstract class Space<S extends Space<S,A>, A extends Atom<S, A>> {}
abstract class Atom <S extends Space<S,A>, A extends Atom<S, A>> {}
抽象类空间{}
抽象类Atom{}
抽象类空间{}
抽象类Atom{}
或者,我想,如果你愿意的话
abstract class Space<S extends Space<S,A>, A extends Atom<S, A>> {}
abstract class Atom <S extends Space<S,A>, A extends Atom<S, A>> {}
抽象类空间{}
抽象类Atom{}
谢谢你,“汤姆·霍丁-塔克林”,我已将你的答案纳入其中,
另外,下面的代码演示了
更改列表类型参数的必要性(如果需要原子列表)
接口空间{
列表谢谢你,“汤姆·霍丁-塔克林”,我已经加入了你的答案,
另外,下面的代码演示了
更改列表类型参数的必要性(如果需要原子列表)
接口空间{
List我不会试图用泛型来解决这个问题。相反,提供一个总是创建匹配对象的工厂
class UniverseFactory {
public Space getSpace();
public Atom getAtom();
}
然后,您可以在实现中执行类型检查,以确保只使用匹配的对象。我不会尝试用泛型解决这个问题。相反,请提供一个始终创建匹配对象的工厂
class UniverseFactory {
public Space getSpace();
public Atom getAtom();
}
然后,您可以在实现中执行类型检查,以确保只使用匹配的对象。这对我来说是可行的,尽管我对所有这些通用约束感到非常困惑。这意味着我不能保证它能做到它应该做的事:
interface ISpace<S extends ISpace<S, A>, A extends IAtom<S, A>> {
List<? extends IAtom<S, A>> getList(); //// CHANGED
}
interface IAtom<S extends ISpace<S, A>, A extends IAtom<S, A>> {
S getSpace();
}
abstract class Space<S extends Space<S, A>, A extends Atom<S, A>>
implements ISpace<S, A> {
private final List<Atom<S, A>> atoms = new LinkedList<Atom<S, A>>(); ////CHANGED
public Space() {
}
public Space<S, A> getSpace() {
return this;
}
@Override
public List<Atom<S, A>> getList() { //// CHANGED
return atoms;
}
}
abstract class Atom<S extends Space<S, A>, A extends Atom<S, A>>
implements IAtom<S, A> {
private final S space;
public Atom(S someSpace) {
this.space = someSpace;
space.getList().add(this);
}
@Override
public S getSpace() {
return space;
}
public Atom<S, A> getAtom() {
return this;
}
}
class Space1 extends Space<Space1, Atom1> {
public Space1() {
}
}
class Atom1 extends Atom<Space1, Atom1> {
public Atom1(Space1 someSpace) {
super(someSpace);
}
}
接口空间{
列表这对我来说很有效,尽管我对所有这些通用约束感到困惑。这意味着我不能保证它能做它应该做的事情:
interface ISpace<S extends ISpace<S, A>, A extends IAtom<S, A>> {
List<? extends IAtom<S, A>> getList(); //// CHANGED
}
interface IAtom<S extends ISpace<S, A>, A extends IAtom<S, A>> {
S getSpace();
}
abstract class Space<S extends Space<S, A>, A extends Atom<S, A>>
implements ISpace<S, A> {
private final List<Atom<S, A>> atoms = new LinkedList<Atom<S, A>>(); ////CHANGED
public Space() {
}
public Space<S, A> getSpace() {
return this;
}
@Override
public List<Atom<S, A>> getList() { //// CHANGED
return atoms;
}
}
abstract class Atom<S extends Space<S, A>, A extends Atom<S, A>>
implements IAtom<S, A> {
private final S space;
public Atom(S someSpace) {
this.space = someSpace;
space.getList().add(this);
}
@Override
public S getSpace() {
return space;
}
public Atom<S, A> getAtom() {
return this;
}
}
class Space1 extends Space<Space1, Atom1> {
public Space1() {
}
}
class Atom1 extends Atom<Space1, Atom1> {
public Atom1(Space1 someSpace) {
super(someSpace);
}
}
接口空间{
ListOk我要咬一口..你为什么要这样做?:)这是你的实际抽象,还是仅仅是问题的一个例子?请查看我自己的答案
了解真正的代码示例OK我要咬一口..你为什么要这样做?:)这是你真正的抽象,还是只是问题的一个例子?请看我自己的答案
了解真正的代码示例我倾向于使参数的顺序一致。汤姆,你的建议有效,但一个非常特殊的东西不起作用(非常奇怪),请在我的“答案”中查看整个代码,我希望你能告诉我问题出在哪里?谢谢,我会尽量使参数的顺序保持一致。汤姆,你的建议有效,但一个非常特殊的东西不起作用(非常奇怪),请在我的“答案”中查看整个代码,我希望您能告诉我问题出在哪里?谢谢您可能还需要向Atom添加一个方法:抽象a getThis();并使用它而不是原始this。正如我所说,如果没有?扩展,它将不起作用。而且,a getThis(){返回此;}
也不起作用:(是的!找到了一个解决方案:列表您可能还需要向Atom添加一个方法:abstract a getThis();并使用该方法而不是原始this。正如我所说的,如果没有?扩展,它将不起作用。而且,a getThis(){return this;}
也不起作用:(是的!找到了一个解决方案:ListYes,这也有效,谢谢!所以“秘密”是用比接口定义更具体的类型覆盖getList()。是的,这也有效,谢谢!所以“秘密”是用比接口定义更具体的类型覆盖getList()。