【问题标题】:Eclipse Generics Issue - Workaround?Eclipse 泛型问题 - 解决方法?
【发布时间】:2013-11-25 19:38:37
【问题描述】:

鉴于以下类型签名,我可以使用 JDK 6 和 JDK 7 在 Maven 下编译和运行代码,但 Eclipse 给出了“绑定不匹配:类型 F 不是有界参数@的有效替代品” TupleVisitor 中出现Field<TP,F> 类型的 987654322@" 错误。

我相信我需要这些类型,尽管我知道考虑到精简的示例,这很难激发。任何人都可以提出一个让我继续在 Eclipse 中工作的解决方法吗?

public abstract class Tuple<F extends Field<TP, F>, TP extends Tuple<F, TP>>

public class VariableTuple<F extends Field<VariableTuple<F>, F>> extends Tuple<F, VariableTuple<F>>

public class ConstantTuple<F extends Field<ConstantTuple<F>, F>> extends Tuple<F, ConstantTuple<F>>

public class Field<TP extends Tuple<F, TP>, F extends Field<TP, F>>

public class ConstantField extends Field<ConstantTuple<ConstantField>, ConstantField>

public class VariableField extends Field<VariableTuple<VariableField>, VariableField>

public interface TupleVisitor {
  public <F extends Field<VariableTuple<F>, F>> void visit(VariableTuple<F> tuple, F field); //Eclipse error

  public <F extends Field<ConstantTuple<F>, F>> void visit(ConstantTuple<F> tuple, F field); //Eclipse error
}

提交错误:https://bugs.eclipse.org/bugs/show_bug.cgi?id=422503

没有发现简单的解决方法。虽然 Rohit Jain 的回答不适用于访问者模式,但我采纳了他的后续建议并从 Field 中删除了 F 作为类型参数。

【问题讨论】:

  • 当前为项目设置的 java 编译器合规级别是什么?
  • Eclipse 合规级别:JavaSE-1.6。
  • Maven 源/目标级别 - 1.6.
  • 我会注意到,将两者都提高到 1.7 并不能解决问题。
  • @AdamAugusta 令人惊讶的是,如果您在接口TupleVisitor 中声明类型变量F,它工作正常。这让我大吃一惊。

标签: java eclipse generics


【解决方案1】:

这似乎是 Eclipse 的一个错误,因为它在 javac 下对我来说也编译得很好。事实上,我发现与 eclipse 相关的自引用 Java 泛型相关的 bug 很少,但这并不存在。所以,也许你应该提交一份。

至于解决方法,我刚刚找到了一个,我怀疑你会喜欢它,因为你必须使你的界面通用。是的,你没听错。用接口本身声明类型参数,使代码编译得很好。下面是编译代码:

interface TupleVisitor<E extends Field<VariableTuple<E>, E>, 
                       F extends Field<ConstantTuple<F>, F>>  {
   void visit(VariableTuple<E> tuple, E field);
   void visit(ConstantTuple<F> tuple, F field);
}

当然有两个类型变量,因为它们的界限是不同的。检查这是否适合您的需要,因为这听起来确实很奇怪,因为类型参数的数量取决于 Tuple 类的实现者总数(实际上很奇怪,不是吗?)。否则你必须做一些其他的改变。

【讨论】:

  • 我喜欢它。为了让访问者模式发挥作用,ConstantTuple 和 VariableTuple 都有 accept 方法。我可以简单地将原始类型用于接受方法和访问者实现,在上游进行强制转换。不是最整洁的方法,但它让我再次感动。
  • 这是一个严重的警告,但如果我没有得到解决这些问题的答案,我会接受你的。感谢您的帮助!
  • @AdamAugusta 删除泛型,并退回到铸造方法虽然不是一个好方法。不过,如果您可以重构您的类以稍微简化泛型类型,那么对您来说可能会很容易。当然,您可以随时接受答案。
【解决方案2】:

问题可能是调用者提供了类型参数。鉴于您的声明,有人可以声明

class ReallyConstantField extends ConstantField {}

然后调用TupleVisitor.visit,同时为F 提供ReallyConstantFieldvisit 方法的类型约束将读取

ReallyConstantField extends Field<ConstantTuple<ReallyConstantField>, ReallyConstantField>

所以我们使用ConstantTuple&lt;ReallyConstantField&gt;。然后该类的类型约束将读取

ReallyConstantField extends Field<ConstantTuple<ReallyConstantField>, ReallyConstantField>

这是不正确的,因为ReallyConstantField 是一个ConstantField 这是一个Field&lt;ConstantTuple&lt;ConstantField&gt;, ConstantField&gt;,这是一个不可转换的类型。

也就是说,即使您声明了带有extends 绑定的类型参数,唯一有效的类型参数是单一类型。也就是说,您根本不需要类型参数,只需声明:

void visit(ConstantTuple<ConstantField> tuple, ConstantField field);

更新

顺便说一句,如果这些应该是,如示例所示,并行类层次结构在不同层次结构的类之间具有一一对应关系,则有一种更简单的方法来编写泛型:

abstract class Tuple<F extends Field<TP, F>, TP extends Tuple<F, TP>> {}

class VariableTuple extends Tuple<VariableField, VariableTuple> {}

class ConstantTuple extends Tuple<ConstantField, ConstantTuple> {}

class Field<TP extends Tuple<F, TP>, F extends Field<TP, F>> {}

class ConstantField extends Field<ConstantTuple, ConstantField> {}

class VariableField extends Field<VariableTuple, VariableField> {}

interface TupleVisitor {
  public void visit(VariableTuple tuple, VariableField field);

  public void visit(ConstantTuple tuple, ConstantField field);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-22
    相关资源
    最近更新 更多