使用javac 8编译代码时使用javac 6可以正常编写Java类型错误

时间:2016-10-17 14:03:09

标签: java typeerror

我有这个类,这是我在从Java 6移植到Java 8的项目中找到的一些代码的简化:

public class Unification {

    final class Box<A> {}

    final class MyMap<A, B extends Box<? extends A>> {}

    MyMap<?, ?> getMap() {
        return new MyMap<Object, Box<Object>>();
    }

    <A, B extends Box<? extends A>> void setMap(final MyMap<A, B> m) {}

    void compileError() {
        setMap(getMap());
    }

}

仅仅展示问题是一个非常小的例子,实际的代码更有意义。这个问题似乎很普遍,因此是一个抽象的例子。核心问题如下:由于某种原因,javac不希望接受类型为MyMap<?, ?>的表达式作为setMap()方法的参数,即使根据我的理解,这应该是好的-typed。

代码使用javac 6编译时没有错误,但是当我使用javac 8时,我得到了这个不起眼的错误消息:

C:\System9\KWS_sparse\sourcesNG\Domain\src\uz\Unification.java (21:9) error: method setMap in class Unification cannot be applied to given types;
required: Unification.MyMap<A,B>
found: Unification.MyMap<CAP#1,CAP#2>
reason: inference variable A has incompatible bounds
equality constraints: CAP#1
lower bounds: Object
where A,B are type-variables:
A extends Object declared in method <A,B>setMap(Unification.MyMap<A,B>)
B extends Unification.Box<? extends A> declared in method <A,B>setMap(Unification.MyMap<A,B>)
where CAP#1,CAP#2 are fresh type-variables:
CAP#1 extends Object from capture of ?
CAP#2 extends Unification.Box<? extends CAP#1> from capture of ?

错误消息似乎表明找不到MyMap的第一个类型参数的统一,javac无法找到与CAP#1统一的类型,setMap()表示第一个通配符参数实际参数AsetMap(),它是A形式参数的相应类型参数。虽然在我看来CAP#1getMap()应该是完全一致的,但它们都代表了通过删除Map签名中的实际类型而引入的存在类型。

有人能发现这里出了什么问题吗? javac 6错误地接受了这段代码吗?另外,是否有一种不太过于干扰(和javac 6兼容)的方式来指导javac 8走向正确的统一?

编辑:我尝试了从stackoverflow.com/questions/23063474/引入变量的建议,但这似乎没有帮助,我得到相同的编译错误。

EDIT2:澄清了示例代码的“意图”。

EDIT3:将MyMap重命名为Map,显然定义自定义Route::resource creates multiple routes to handle a variety of RESTful actions on the resource类型太麻烦了。

1 个答案:

答案 0 :(得分:0)

通过引入中间方法可以避免这个问题,从而迫使javac分两个阶段进行类型推断。第一种方法只接受一个类型参数,并将第二个作为通配符。 Javac能够正确地推断出此方法的单一类型参数。然后,第二个原始方法能够从提供的参数中正确地推断出第二个类型参数。

public class Unification {

    final class Box<A> {}

    final class MyMap<A, B extends Box<? extends A>> {}

    MyMap<?, ?> getMap() {
        return new MyMap<Object, Box<Object>>();
    }

    <A> void setMap(final MyMap<A, ?> m) {
        doSetMap(m);
    }

    <A, B extends Box<? extends A>> void doSetMap(final MyMap<A, B> m) {}

    void worksFineNow() {
        setMap(getMap());
    }

}