【问题标题】:Type safety error with generic class泛型类的类型安全错误
【发布时间】:2015-05-15 09:40:32
【问题描述】:

编辑:设置

有一个从 ProgramFactory 调用方法的解析器,该工厂使用表达式、语句、类型和程序,如下面的实现的标题中所示。 ProgramFactory 实现了 IProgramFactory,它是一个看起来像这样的接口 public interface IProgramFactory<E, S, T, P>

我似乎遇到的问题是 Expression 也是通用的,我不知道如何在实现中正确处理(在标头和方法中)

当只有返回类型是 Expression 类型时,它似乎可以工作,如下所示

    @Override
public Expression<Boolean> createTrue(SourceLocation sourceLocation) {
    True expr = new True();
    return expr;
}

但不是当变量也是表达式类型时

我这样做是为了返回类型和参数类型的通配符 不必相同

public abstract class BinaryExpression<T, R> extends Expression<T>{
    Expression<R> left;
    Expression<R> right;
}

在一个接口的实现中,我似乎一遍又一遍地遇到同样的问题。

Expression is a raw type. References to generic type Expression<T> should be parameterized

问题是当我参数化这些表达式时,它们告诉我接​​口没有这个方法。

The method createAddition(Expression<Double>, Expression<Double>, SourceLocation) of type ProgramFactory must override or 
 implement a supertype method

这就是实现的样子

@Override
public Expression<Double> createAddition(Expression left, Expression right, SourceLocation sourceLocation) {
    Addition expr = new Addition(left, right);
    return expr;
}

界面是这样的

/** An expression that evaluates to the sum of the given expressions */
E createAddition(E left, E right, SourceLocation sourceLocation);

这是 Addition 类的样子

public class Addition extends BinaryExpression<Double, Double>{ 
    public Addition(Expression<Double> left, Expression<Double> right){
        this.left = left;
        this.right= right;
    }

     @Override
     public Double eval() {
         Double sum = left.eval() + right.eval();
         return sum;
     }
}

这就是 Expression 类的样子

public abstract class Expression<T> {
    public abstract T eval();
}

这是实现的标头的样子

public class ProgramFactory implements IProgramFactory<Expression<?>, Statement, Type, Program>{

【问题讨论】:

  • 缺少重要的位,前两个sn-ps的接口和类声明(ProgramFactory和实现类)

标签: java generics types interface abstract


【解决方案1】:

您没有提供完整的接口实现。所以我可以认为它是这样的:

class MyImplementation implements Interface<Expression> {
        @Override
        public Expression<Double> createAddition(Expression left, Expression right, SourceLocation sourceLocation) {
            Addition expr = new Addition(left, right);
            return expr;
        }
}

但应该是这样的:

class MyImplementation implements Interface<Expression<Double>> {
        @Override
        public Expression<Double> createAddition(Expression<Double> left, Expression<Double> right, SourceLocation sourceLocation) {
             Addition expr = new Addition(left, right);
             return expr;
        }
}

这是原始类型Expression = |Expression&lt;E&gt;|。并在您的方法参数中使用简单的Expression 擦除类型参数。您不能在接口实现中声明原始Expression 并使用类型参数(CTE)的参数覆盖方法。把类型参数想象成简单的别名。

【讨论】:

  • 这里的问题是 Expression 是泛型的,并且实现使用多种类型的表达式,因此我不能将 Expression 作为接口后面的参数
  • @Goatherder95 你应该真正描述一下设置是什么以及你想要实现什么,因为这看起来很像XY problem
  • 如果是这样并且你真的需要这样的实现,你可以声明Interface&lt;Expression&lt;?&gt;&gt;并使用public Expression&lt;?&gt; createAddition(Expression&lt;?&gt; left, Expression&lt;?&gt; right, SourceLocation sourceLocation),你也可以像&lt;? extends SomeClass&gt;&lt;? super SomeClass&gt;一样绑定它。但请记住,您还应该在类类型声明中更改它。
  • 通配符的问题在于,您可能希望所有三个(左、右和返回值)都属于同一类型,而通配符并非如此。
【解决方案2】:

您的表达式类应如下所示,

class Expression<T> {
  ....
}

您的界面应如下所示,

@Override
public Expression<?> createAddition(Expression<?> left, Expression<?> right, SourceLocation sourceLocation) {
     Addition expr = new Addition(left, right);
     return expr;
}

并且还将您的 Expression 类设为通用类。创建你的

它会解决你的问题。

【讨论】:

  • 是的,而且我已经在我的应用程序中使用了这种结构。
  • 这很奇怪,因为Expression&lt;?&gt;肯定不会进入Expresssion&lt;Double&gt;,所以Addition expr = new Addition(left, right);这一行不应该编译。
  • Expression 类是通用的
  • 是通用的,所以我可以处理任何类型的数据。像 Collection> / Collection。如果您在泛型中明确提及该类型,那么它将不接受其他类型。如果你给“?”那么它将接受任何类型。请参阅通配符泛型文档和 Java 规范
  • 但是这种情况下的返回值应该是 Expression
【解决方案3】:

如果你显式参数化接口中的所有参数:

public interface IProgramFactory<T> {
  public Expression<T> createAddition(
      Expression<T> left,
      Expression<T> right,
      SourceLocation sourceLocation
  );
}

那么你可以这样做:

public class ProgramFactory implements IProgramFactory<Double>{
  @Override
  public Expression<Double> createAddition(
      Expression<Double> left,
      Expression<Double> right,
      SourceLocation sourceLocation
  ){
    Expression<Double> expr = new Addition( left, right );
    return expr;
  }
}

【讨论】:

    猜你喜欢
    • 2018-08-26
    • 2013-05-17
    • 1970-01-01
    • 1970-01-01
    • 2021-03-27
    • 2012-04-20
    • 2010-10-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多