java - Java 中的自引用泛型

标签 java generics nested-generics

我不明白为什么我不能转换自引用泛型。

在 Java 中,我有一个自引用泛型。有一堆事物(Intent),以及查找(解决)这些事物的策略(ResolutionStrategy)。

自引用 Intent 类型定义如下。我想在编译时定义只能接收接受相同意图的 ResolutionStrategy 的类。

public interface Intent<I extends Intent<I, R>, R extends Resolution>
{
    void resolve(ResolutionStrategy<I, R> strategy);

    R getResolution();
}

因此解决策略是:

public interface ResolutionStrategy<I extends Intent<I, R>, R extends Resolution>
{
    R resolve(I intent);
}

因此,当我对这些 Intent 的列表进行操作时,我并不关心它们是什么。但是,我确实想创建特定类型来表示我的域模型中的具体事物。这是一个例子:

public class OrgIntent implements Intent<OrgIntent, IdentifiableResolution>
{
    public final String name;

    public OrgIntent(String name)
    {
        this.name = name;
    }

    @Override
    public void resolve(ResolutionStrategy<OrgIntent, IdentifiableResolution> strategy)
    {
        // Do stuff
    }

    @Override
    public IdentifiableResolution getResolution()
    {
        //Return resolution got from strategy at some point in the past
        return null;
    }
}

IdentifiableResolutionResolution 的简单而无趣的实现。

到目前为止一切都很好。然后计划构建这些 Intent 的漂亮图,然后迭代它们,将每个传递给 ResolutionStrategyFactory 以获得解决它们的相关策略。但是,我无法将 OrgIntent 转换为任何足以添加到列表中的通用内容!

private <I extends Intent<I, R>, R extends Resolution> DirectedAcyclicGraph<Intent<I, R>, DefaultEdge> buildGraph(Declaration declaration) throws CycleFoundException
{
        DirectedAcyclicGraph<Intent<I, R>, DefaultEdge> dag = new DirectedAcyclicGraph<>(DefaultEdge.class);
        // Does not compile
        Intent<I, R> orgIntent = new OrgIntent("some name");
        // Compiles, but then not a valid argument to dag.addVertex()
        Intent<OrgIntent, IdentifiableResolution> orgIntent = new OrgIntent("some name");
        // Compiles, but then not a valid argument to dag.addVertex()
        OrgIntent orgIntent = new OrgIntent("some name");

        //Then do this
        dag.addVertex(orgIntent);
        ...

我应该将 orgIntent 声明为什么?有什么想法吗?

更新

感谢@zapl,我意识到方法定义中的泛型类型参数完全是转移注意力。

这可以编译,但大概意味着我可以以某种方式拥有一个 Intent,它被泛化为将任何旧的废话作为第一个泛型类型?

private DirectedAcyclicGraph<Intent<?, ? extends Resolution>, DefaultEdge> buildGraph(Declaration declaration) throws CycleFoundException
{
    DirectedAcyclicGraph<Intent<?, ? extends Resolution>, DefaultEdge> dag = new DirectedAcyclicGraph<>(DefaultEdge.class);
    OrgIntent orgIntent = new OrgIntent("some name");
    dag.addVertex(orgIntent);

最佳答案

就像 zapl 在评论中建议的那样,泛型没有提供足够强大的类型保证来处理您所描述的模式。特别是因为 Java 泛型是非具体化的,所以 JVM 无法在转换为更通用的类型 ( OrgIntent ) 后恢复更具体的类型 ( Intent<I, R> )。由于通用类型信息在运行时丢失,JVM 只能依赖具体的原始类型 (Intent)。

这是同样的原因,例如,您不能定义具有不同通用签名但具有相同具体签名的两个方法 - foo(List<String>)foo(List<Integer>)两者都变得简单 foo(List)在运行时,因此编译器不允许您在同一个类中定义两个这样的方法。

从广义上讲(恐怕我对您的用例的理解不够透彻,无法更精确)解决方案是通过关联的 Class object 显式地将对象与所需的泛型相关联。或 TypeToken .例如,您可能能够使以下签名起作用:

R resolve(Class<I> intentClass, I intent);

Effective Java Item 29: Consider typesafe heterogeneous containers 中提供的建议也应该有帮助:

Sometimes, however, you need more flexibility [than a fixed number of type parameters].... The idea is to parameterize the key instead of the container. Then present the parameterized key to the container to insert or retrieve a value. The generic type system is used to guarantee that the type of the value agrees with its key.

...

Java's type system is not powerful enough to express [the type relationship between keys and values]. But we know that it’s true, and we take advantage of it when it comes time to retrieve a favorite.

关于java - Java 中的自引用泛型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37572095/

相关文章:

java - 使用无参数构造函数创建代理类

java - 正则表达式查找具有任何字母的精确计数的单词

java - 库中缺少元素

java - 使用接口(interface)时,为什么多态性在泛型方法中不起作用?

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

java - 简单情况下的 AsyncTask 替代方案

generics - 使用泛型进行对象转换

.net - 如何有效地打开表达式结果?

java - 递归方法中的泛型

java - 当字段由字符串名称引用时,如何获取通用对象上字段的类