【问题标题】:How to write a generic method in Java to support comparison and arithmetic operations如何在 Java 中编写泛型方法以支持比较和算术运算
【发布时间】:2012-01-24 18:27:09
【问题描述】:

我想在 java 中编写一个通用方法,如下所示:

public <T extends Number & Comparable<T>> void test(T[] a){
    T b=a[0];
    if(a[0]>0){
        a[0]*=a[0];
        b+=a[1];
    }
}

然后,我可以为该方法提供 Integer[]Double[] 或其他 Number 子类型。但是我上面尝试的代码给了我错误。

请帮助我。谢谢。

【问题讨论】:

  • 您要解决的问题是什么? Java 不支持这种泛型操作。如果我们了解用例,也许我们可以提出替代方案。例如,我发现使用包装类数组(如Integer[])而不是原始数组(如int[])从来都不是一个好主意。您是否有理由需要 IntegerDouble 而不是 intdouble
  • @DanielPryden:我正在尝试解决:编写一个接受 int[]、float[] 或 double[] 的方法,在其中我需要进行一些比较和算术,然后返回相同的数组类型 int[],或 float[],或 double[]。
  • 那么你能做的最好的就是将你的实际计算分解成一个在double[]上运行并返回double[]的方法(因为doubleintfloat)。您仍然需要另外两种方法来支持 int[]float[] 参数。

标签: java generics


【解决方案1】:

除了原语之外的所有类型(包括推断的泛型类型)都是不支持算术运算的对象(包装类使用装箱/拆箱来获得已知的伪行为)

类型擦除使编译后的代码使用强制转换来获得正确的行为(即在运行时 JVM 不知道传递了什么类型,它需要知道才能获得正确的装箱/拆箱行为)

唯一(真正的)解决方案是为您想要支持的所有原语提供实现

【讨论】:

  • 感谢您的回答。是否有任何更短、更优雅的方式来执行其他复制代码?
  • @littleEinstein:如果你只是想做比较,你可以使用compareTo() method of Comparable&lt;T&gt;。但是您不能在 Java 中对 Number 实例执行算术运算。
  • @DanielPryden:对。但是做算术对于我的方法来说是必须的。在这种情况下,你有一个好的解决方案而无需编写重复的代码吗?
  • @littleEinstein:正如我在对您的问题的评论中所写的,我们需要的是对您的用例的解释。 为什么你要这样做?你能把所有东西都上载到double,然后使用它吗? (double 可以保存除long 之外的任何其他数值类型的所有值而不会丢失精度。)
【解决方案2】:

你不能在 Java 中使用泛型来做到这一点。例如,这是 C++ 的一个好处。

在某种程度上,您可以将其定义为“奇怪”,因为它可以在 Java 的原始包装器上使用运算符。但那是因为您不能在原始包装器的超类 java.lang.Number 上使用运算符。

一些资源:

【讨论】:

  • 好的,现在我明白了原因。但是,如果我希望我的方法能够用于 Integer[]、Double[]、Float[],如何实际重用代码?
  • 这就是 Java 泛型中令人讨厌的部分:你根本做不到。您可能会尝试的唯一方法是始终使用 double 并将使用前后的数据转换为 double。
【解决方案3】:

你有Comparable,所以如果我们有zeroa[0]&gt;0 可以替换为a[0].compareTo(zero) &gt; 0(不,我想是&lt; 0,我记不得了)。但是现在我们已经用完了来自Double 之类的有用的东西。

如果Double 和朋友不是java.lang.Comparable,我们可以提供我们自己的java.util.Comparator。那就是我们在数据对象之外执行比较。我们也可以做加法和乘法。

public interface Testor<T> { // Choose a better name...
    boolean isStriclyPositive(T value);
    T add(T lhs, T rhs);
    T square(T value);
}

static final Testor<Integer> INTEGER_TESTOR = new Testor<>() { // Java SE 7 diamond.
    public boolean isStriclyPositive(Integer value) { return value > 0; }
    public Integer add(Integer lhs, Integer rhs) { return lhs + rhs; }
    public Integer square(Integer value) { return value*value; }
}
// ... same for Double, etc.; can't use an enum :( ...

test(new Integer[] { 42, 1972, 86 }, INTEGER_TESTOR);

public <T> void test(T[] a, Testor<T> testor) {
    T b = a[0];
    if (testor.isStrictlyPositive(a[0])) {
        a[0] = testor.square(a[0]);
        b = testor.add(b, a[1]);
    }
}

注意Short 之类的内容,将其中两个相加将得到int

(通常的堆栈溢出免责声明:与其试图编译代码相比。)

【讨论】:

    猜你喜欢
    • 2021-05-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-06-01
    • 2019-11-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多