我可以在Java泛型中传递复杂类型结构吗?

12

我目前正在尝试使用Java接口和泛型实现一个概念模型的API。该模型(Transmodel V5.0)详细描述了实体关系模型,但没有指定一些基本类型的使用。例如,各种实体的标识符类型或用于建立序列排序的类型未定义。

由于我希望尽可能保持API的通用性,因此我开始使用泛型来配置这些细节。我不想对类型做出任何假设,包括不假设任何东西是一致的。每个实体都可以具有不同的标识符类型,每个序列都可以使用不同的类型进行排序。

我面临的问题是,一旦一个实体引用另一个实体,复杂性就会迅速增加--我不仅需要传递其标识符类型,还需要传递配置引用实体所需的所有内容。

例如,我有:

/**
 * @param <ID> The type for the identifier of this entity.
 * @param <ID_JP> The type identifying journey patterns.
 * @param <OP_JP> The ordering used for points in journey patterns.
 * @param <JP> The type of journey pattern referenced by this entity.
 */
public interface VehicleJourney<
        ID,
        ID_JP, OP_JP extends Comparable<OP_JP>, JP extends JourneyPattern<ID_JP, OP_JP>
    > extends IdentifiableObject<ID>
{
    JP getJourneyPattern();
}

我仍然能够阅读并理解它,但有些内容过于冗长。而且像VehicleJourney这样的实体可以被其他实体引用,这使得类型参数列表变得很庞大。这是我能想到的最小的非平凡示例。

是否有一种方法可以创建一个单独的Java实体来建模整个类型系统的配置?我想到的是,它将附有所有标识符类型和排序类型,并可以作为一个整体传递,从而将上面的示例转换为类似于以下内容:

public interface VehicleJourney<CONF, JP extends JourneyPattern<CONF>> 
       extends IdentifiableObject<???>
{
    JP getJourneyPattern();
}
在带有问号的位置,需要从CONF中提取VehicleJourney标识符的类型。如果这是可行的,那么复杂度应该保持在可管理的水平。

我相信C++有一种方法可以完成这个任务,但无论是什么,都会让我的头炸裂。 - ajb
没有继承,我不这么认为。 - Radiodef
你可以声明新类型,不需要参数,通过赋予有意义的名称来扩展复杂类型。不幸的是,这会产生讨厌的副作用。 - Basilevs
@ajb,C++有typedefs,但它们在编译器输出中不起作用 :( - Basilevs
@Basilevs, Rob N:Scala 可能是一个选择——那些抽象类型成员看起来真是太棒了。在我阅读Scala的类型系统之前,让我们先看看是否可以得到我的问题的明确答案。 - Peter Becker
显示剩余4条评论
1个回答

1

这可能不会很美观。

您可以使用未锚定类型,并通过具有将id和比较器类型分组的类型来简化:

public interface Meta<ID, COMP extends Comparable<COMP>> {

}

public interface IdentifiableObject<M extends Meta<?, ?>> {

}

public interface JourneyPattern<M extends Meta<?, ?>>
        extends IdentifiableObject<M> {

}

public interface VehicleJourney<M extends Meta<?, ?>, JP extends JourneyPattern<?>>
        extends IdentifiableObject<M> {

}

您不需要为类型的嵌套类型命名以进行锚定。当您拥有具体类(甚至子接口)时,所有类型都将被锚定。例如:

public class VehicleJourneyImplMeta implements Meta<String, String> {

}

public class VehicleJourneyImpl extends IdentifiableObjectBase<VehicleJourneyImplMeta> 
        implements VehicleJourney<
                VehicleJourneyImplMeta, 
                JourneyPattern<Meta<Integer, String>>> {

}

您需要通过使用中间类(很可能是匿名类)来委托访问Meta中的类型:
VehicleJourney<Meta<String, String>, ?> v = something();
Meta<String, String> m = v.getObjectMeta();
String idOfV = m.getId();

通过在方法级别使用各种类型参数,您可能会使其工作。

我认为您(以及我和大多数人)真正想要的是像这样的东西:

public interface VehicleJourney<M extends Meta<?, ?>, JP extends JourneyPattern<?>>
        extends IdentifiableObject<M> {

        public JP.M.ID getIdOfReferencedX();
}

很遗憾,Java不支持将JP.M.ID作为返回类型进行类型定义。也许有人会提出一个JSR来解决这个问题。如果我没记错的话,字节码包含了泛型类型参数的名称。

我认为类型参数是“擦除”的,因此可能不容易回溯。 - Niels Bech Nielsen

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