创建自己的Java不可变持久列表 - 输入问题

时间:2014-07-05 22:30:37

标签: java list persistent typing

我正在尝试学习如何创建一个不可变的持久列表。现在我的实现是在java中,虽然我对这个概念更感兴趣,并想出如何与静态类型很好地协作。

我的第一个实施工作正在进行中。它有final int sizefinal T headfinal PersistentList<T> tail字段。它只是一个单链表,每个节点指向同一PersistentList<T>类型(通过tail字段)的另一个节点,或者在列表末尾的情况下指向null。这就是问题所在,我不想在任何地方进行null检查,也不想使用null来表示列表/空列表的结尾。我想用新的EmptyList对象表示一个空列表,总是是我的PersistentList抽象类中的最后一个节点。这就是clojure doesEric Lippert demonstrated(在C#中)。

我的问题是,由于这个新的EmptyList对象属于不同的类型,我在正确的位置指定正确的类型时会出现问题,并且编译器会抱怨。

我创建了一个抽象类IPersistentList,并从中派生了PersistentListEmptyList。目标是具有以下列表结构:

|PersistentList<T>| --> |PersistentList<T>| --> |EmptyList<T>|

现在像tail或静态create函数这样的方法需要能够返回PersistentList<T>EmptyList<T>实例,具体取决于它是否是最后一个节点列表,但我如何指定正确的返回类型?我的猜测是总是返回父抽象类IPersistentList<T>的类型。但这需要我总是强制派生类,感觉非常脏,编译器仍在抱怨。我也不想要一个解决方案,其中需要客户端代码来初始化类型列表然后必须进行转换。我希望它是透明的。

这是我的代码gist。这是错误:

persistent_list/src/main/java/com/benreinhart/persistentlist/PersistentList.java:15: error: constructor PersistentList in class PersistentList<T#2> cannot be applied to given types;
    PersistentList<T> p = new PersistentList<T>(head, PersistentList.empty(), 1);
                          ^
  required: T#1,IPersistentList<T#1>,int
  found: T#1,IPersistentList<Object>,int
  reason: actual argument IPersistentList<Object> cannot be converted to IPersistentList<T#1> by method invocation conversion
  where T#1,T#2 are type-variables:
    T#1 extends Object declared in method <T#1>create(T#1)
    T#2 extends Object declared in class PersistentList
Note: persistent_list/src/main/java/com/benreinhart/persistentlist/PersistentList.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error

正如您所看到的,编译器抱怨我尝试从EmptyList<T>投射到IPersistentList<T>

一般来说,在给定静态类型约束的情况下,我会如何做这样的事情?无论如何,如果是这样的话,我可以在没有到处投影的情况下完成这个吗?我尽力遵循它的数据结构的clojure源代码,但是那里有很多其他的东西,我对静态类型(和java)的语言很新,所以我不能掌握所有这些。

提前致谢!

1 个答案:

答案 0 :(得分:1)

问题是Java无法推断empty()方法的类型参数。它放弃并假定它是ObjectEmptyList<Object>无法投放到IPersistentList<T>

要解决此问题,您可以明确传递它:

PersistentList<T> p = new PersistentList<T>(head, PersistentList.<T>empty(), 1);

empty()提取到临时局部变量:

IPersistentList<T> empty = PersistentList.empty();
PersistentList<T> p = new PersistentList<T>(head, empty, 1);

或使用Java 8,它应该能够处理这种情况。

请点击此处了解详情:http://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html#target_types