当前位置: 首页 > 面试题库 >

Java CRTP和通配符:代码在Eclipse中编译,但不能在`javac`中编译

郭志泽
2023-03-14
问题内容

抱歉,标题含糊。我有这段代码可以在Eclipse Juno(4.2)上编译,但不能在javac(1.7.0_09)上编译:

package test;

public final class Test {
    public static class N<T extends N<T>> {}

    public static class R<T extends N<T>> {
        public T o;
    }

    public <T extends N<T>> void p(final T n) {}

    public void v(final R<?> r) {
        p(r.o);       // <-- javac fails on this line
    }
}

错误是:

Test.java:13:错误:类Test中的方法p无法应用于给定类型;
        p(ro);
        ^
  要求:T
  找到:N <CAP#1>
  原因:推断的类型不符合声明的边界
    推断:N <CAP#1>
    绑定:N <N <CAP#1 >>
  其中T是类型变量:
    T扩展了方法<T> p(T)中声明的N <T>
  CAP#1是新鲜的类型变量:
    CAP#1从捕获?扩展了N <CAP#1>。
1个错误

所以问题是:

  1. 这是javacBug还是Eclipse错误?

  2. 有什么办法可以在javac不更改v方法签名的情况下进行编译(即保留通配符)?

我知道将其更改为<T extends N<T>> void v(final R<T> r)确实可以使其编译,但是我想知道是否有办法首先避免这种情况。另外,由于内容的类型需要严格的约束,p因此无法将方法更改为。<T extendsN<?>> void p(final T n)``T extends N<T>


问题答案:

通配符的局限性在于它们会破坏T extends X<T>类型参数允许的递归表达式。基于以下几点,我们知道您要执行的操作是安全的:

  1. r.o是类型T(由声明R),是或扩展N<T>
  2. 该方法p采用类型的参数T(由声明p),该参数也为或扩展N<T>
  3. 因此,即使r键入为R<?>,从p(r.o)理论上讲呼叫也应该合法。

这可能是eclipse编译器的原因(已知它会为javac没有的某些细微差别提供正确的余量)。

假设您想使用javac进行编译并且不能v像您提到的那样更改签名,那么您可以做的最好的事情就是使用原始类型,该类型“选择退出”泛型类型检查:

public void v(final R<?> r) {
    //necessary to placate javac - this is okay because [insert above reasoning]
    @SuppressWarnings("rawtypes")
    N nRaw = r.o;
    p(nRaw);
}


 类似资料:
  • 问题内容: 我不得不发现我的项目中有Java代码,该代码可以在Eclipse中编译并正常运行,但是会在javac中引发编译错误。 一个完整的代码段: javac中的编译返回: 现在,此错误阻止在Maven中构建项目。由于Eclipse编译器具有更高的容忍度,因此我现在不得不假设代码段的定义和用法如上所述,静态方法不是有效的Java吗? 问题答案: 似乎Sun的1.6 JDK无法推断正确的类型。以下

  • 问题内容: 注意:这是从Comparable和Comparator合约衍生出来的,涉及null 该代码可以在Eclipse(20090920-1017)中编译并正常运行 但是它不能在上编译javac 1.6.0_17。这是错误消息: 有人可以解释为什么差异吗?这是一个错误吗?如果是这样,谁有错误? 问题答案: 这是一个已确认的错误:错误ID 6468354。这是相关的摘录: 此问题是由以下事实引起

  • 问题内容: 我知道过去有一些关于在Eclipse中编译但不能在命令行中编译的问题,但是我还无法找到解决问题的答案。 特别是,我认为我可以设置eclipse以使用我的系统编译器,但这仍然不能解决问题。 我目前正在检查以下内容:“首选项-> Java->已安装的JRE”。 它仅包含一个JRE,这是我的系统之一。 这是问题的细节 我有一个Java通用类,将Enum类型作为参数,如下所示: 我在类中的某个

  • 下面的代码在g7.2.0中编译成功(编译标志是),但在clang 5.0.0中编译失败(使用相同的标志,)和vc 15.4(编译标志是): 哪种编译器行为符合标准?如何将该模板应用更改为在clang上编译? 叮当声错误消息: VC错误消息:

  • 最近,我们正在将java构建作业从serverA迁移到serverB,java源代码(包含中文字符)在使用Ant的原始serverA上编译良好( ),但是,当我们将相同的代码签出到新的serverB并运行相同的Ant脚本时,出现了编码错误,如“用于编码GBK的Unmappable character”(Unmappable character for encoding GBK)。(JDK版本相同)

  • 问题内容: 例如 当Eclipse编译Java源代码时,在哪里配置-g标志?(使用Ganymede,但我怀疑在以后的版本中已更改,因此任何答案都可能会有所帮助。) 我需要的是: -G 生成所有调试信息,包括局部变量。默认情况下,仅生成行号和源文件信息。 问题答案: 选择菜单:窗口>首选项> Java>编译器 在那里,您会在“类文件生成”标题下找到几个复选框。