【问题标题】:Java generics issue with overloaded methods重载方法的Java泛型问题
【发布时间】:2016-09-29 13:28:36
【问题描述】:

我有以下类型化接口的层次结构和一个实现:

public interface Operation<T> {

    T add(T object1, T object2);
}

public interface OperationNumeric<T extends Number> extends Operation<T> {

        T add(T number1, T number2);
}

这个实现带有一个重载方法add():

public class OperationFloat implements OperationNumeric<Float> {

        public Float add(Float number1, Float number2) {
                return number1+number2;
        }

        public Float add(Float number1, Integer number2) {
                return number1+number2;
        }
    }

现在我有一个使用 OperationNumericInterface 的方法:

 public Number calculate(Number operand1, Number operand2, OperationNumeric operand) throws Exception {
      return operand.add(operand1, operand2);
}

现在我正在尝试使用两种不同类型的 Float 和 Integer 故意调用 calculate(),如下所示:

  try {
       calculate(2.2f,2, new OperationFloat());
  } catch (Exception e) {
        System.out.println(e.getMessage());
 }

一旦我调用它,Java 一直引用 add(Float, Float) 方法,看不到重载的方法 add(Float, Integer)。

IDEA 建议“未经检查地调用 add(T, T) 作为原始类型的成员 ...”

如何修改我的接口/类以便能够根据需要使用重载方法?

【问题讨论】:

  • 这很有趣。我认为 Java 会将 2 视为 int 并使用 Integer 签名。将2 包裹在Integer(2) 中会发生什么?
  • add(Float, Integer) 不是界面的一部分。如果在OperationNumeric接口上操作,Java为什么要调用这个方法?
  • Q&A 与这个有点相关,因为您应该知道方法调用是如何“选择”的。但是 Turing85 也是对的,编译不会看到重载版本,因为它不是接口的一部分。

标签: java generics overloading


【解决方案1】:

您的解决方案中的基本缺陷是Operation 接口中的两个操作数必须属于同一类型。因此,Float add(Float, Integer) 方法通过接口OperationNumeric&lt;Float&gt; 是不可见的(因为IntegerFloat 没有直接的继承关系)。

如果你想对两个参数使用不同的类型,你实际上需要三个泛型参数(一个用于每个参数,一个用于返回类型)。这将导致这样的界面:

/**
 * @param <O> first parameter-type of operation
 * @param <P> second parameter-type of operation
 * @param <R> result-type of operation
 */
public interface OperationNumeric<O extends Number
                                  , P extends Number
                                  , R extends Number> {
    R add(O number1, P number2);
}

这个接口会这样实现:

OperationNumeric<Float, Float, Float> floatAddition
    = (Float f1, Float f2) -> f1 + f2);

OperationNumeric<Float, Integer, Float> floatIntAddition
    = (Float f, Integer i) -> f + i;

OperationNumeric<Number, Number, Number> numberAddition
    = (Number n1, Number n2) -> n1.doubleValue() + n2.doubleValue();
...

注意numberAddition 的示例。这很可能是最接近您真正想要实现的目标。如果你看一下实现,你会看到操作是在double-values 上完成的,因此你失去了一些特定于类型的属性(例如,加法不是在循环算术中完成的,你不会四舍五入到除法时的下一个最低int 值,...)。可以通过像这样添加一堆instanceof 检查来解决这个问题:

        if ((n1 instanceof Integer) && (n2 instanceof Integer)) {
            return (((Integer) n1) + ((Integer) n2));
        }

【讨论】:

  • 谢谢。我可能会选择这个解决方案!
【解决方案2】:

如果你使用的是接口OperationNumeric operand声明的变量对象,你只能使用该接口中声明的方法。实例化对象的其余方法不可见。尝试正确定义对象,例如:

if (operand instanceof OperationFloat && operand2 instanceof Integer) {
    ((OperationFloat) operand).add(operand1, (Integer)operand2);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-29
    • 1970-01-01
    • 2013-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多