Java 如何以通用方式处理数字?

Java 如何以通用方式处理数字?,java,generics,Java,Generics,我的问题很奇怪,就像是受到一个类处理矩阵运算的启发一样。 尽管这个问题是用C#提出的,并指向了一篇关于 我不明白。Java Number没有add方法,因此您可以使用如下方法: public Number myAdd(Number a, Number b){ return a.add(b); } 那么,如果您希望能够在Java中处理多种类型的数字,该如何处理这种情况呢?就我个人而言,我几乎对所有数字都使用大小数(但这主要是因为我使用的是货币值)。它们处理任何大小的所有数值。因此,在我

我的问题很奇怪,就像是受到一个类处理矩阵运算的启发一样。 尽管这个问题是用C#提出的,并指向了一篇关于

我不明白。Java Number没有add方法,因此您可以使用如下方法:

public Number myAdd(Number a, Number b){
     return a.add(b);
}

那么,如果您希望能够在Java中处理多种类型的数字,该如何处理这种情况呢?

就我个人而言,我几乎对所有数字都使用大小数(但这主要是因为我使用的是货币值)。它们处理任何大小的所有数值。因此,在我看来,它们是一个泛型值,可以在假设的示例中使用,而不是数字抽象类。任何东西都可以转换成大十进制,为什么不使用它呢

public BigDecimal myAdd(BigDecimal a, BigDecimal b) {
    return a.add(b);
}
编辑:为了解决BigBrothers下面的评论,您可以始终使用doubleValue()方法创建自己的泛型方法。唯一的问题是,在某些罕见的情况下,如果有人输入一个大于Double.maxValue的BigDecimal,则可能会丢失精度

public Number myAdd(Number a, Number b) {
    return new BigDecimal(a.doubleValue() + b.doubleValue());
}
BigDecimal是一个数字,因此返回一并不重要

我不明白。Java编号不适用 有一个添加方法

假设
java.lang.Number
确实有一个
add
方法,您将如何定义它的签名?你如何定义它的语义?您将如何处理“混合模式”算法

虽然毫无疑问,回答这些问题并设计一个API是可能的,但结果可能很难正确使用。此外,应用程序需要执行“表示不可知”算法是最不常见的。通常,您希望/需要明确控制算术的执行和转换的发生方式。(Java原语类型升级规则对于人们来说已经够难的了!!)


总之,我认为Sun为我们提供了很好的服务,它没有尝试在数字API中支持算术。

基本问题是Java类型系统非常原始

由于Java中没有密封类型集的概念(Java也不可能像Haskell那样推断类型),因此没有任何方法可以不耍花招地创建一个通用的数字+数字->数字


对于原语(以及可以自动映射到它们的Integer等对象),类型提升和+操作是语言的一部分。(这就是问题的实际部分:当a和b是不同类型时,a+b应该返回什么?)

如果您真的想要这种行为,您必须找到(或创建)您自己的自定义类,该类使用反射或一系列(检查和)强制转换等。即使您使用泛型(记住泛型是类型擦除的),也需要进行转换


我想这些问题是数字如此平淡的部分原因。

你希望结果有多好?如果答案是“基本上足够好”,那么这就足够了:

public Number myAdd(Number a, Number b){
     return a.doubleValue() + b.doubleValue();
}
但是,如果您想要与Java原语的提升语义相匹配的东西,您可能需要自己编写它。然后,您必须找出所有“非标准”
Number
实现组合的规则,包括
BigDecimal
biginger
AtomicDouble
AtomicLong
,org.apache.commons.lang.mutable中的所有内容,以及下周二可能会有人决定编写的任何随机实现


目前还不清楚在大多数情况下正确的做法是什么——例如,如果其中一个参数是Apache Commons的分数,那么将所有内容转换为
BigDecimal
,就不是一个选项;此外,以一般方式进行转换与以一般方式进行加法存在相同的问题。但是在
Number
上有一个
add()
方法需要每个
Number
实现来处理所有这些情况——这可能就是为什么它不存在的原因。

由于其他人指出的原因,你不能添加任何两个数字,但是你可以添加相同类型的数字,结果也将是相同类型的数字。 您可以用Java创建通用算术,如下所示:

interface Arithmetics<T> {
    T add(T val1, T val2);
}

class IntegerArithmetics implements Arithmetics<Integer> {
    Integer add(Integer val1, Integer val2) { return val1 + val2; }
}

//similarly DoubleArithmetics, BigIntegerArithmetics, ...
接口算法{
T加(T值1,T值2);
}
类IntegerArithmetics实现算术{
整数加法(整数val1,整数val2){return val1+val2;}
}
//类似地,双算术、双整数算术。。。

库正好为您这样做。

实现泛型add方法的一种方法是让左手参数推断返回类型

package mixins;

import java.math.BigDecimal;

public class Numbers {

    public static boolean isZ(Number n) {
        return n instanceof Integer || n instanceof Long || n instanceof Short || n instanceof Byte;
    }

    public static boolean isR(Number n) {
        return n instanceof Double || n instanceof Float;
    }

    public static BigDecimal add(BigDecimal a, Number b) {
        if (b instanceof BigDecimal) {
            return a.add((BigDecimal) b);
        } else if (isZ(b)) {
            return a.add(new BigDecimal(b.longValue()));
        } else if (isR(b)) {
            return a.add(new BigDecimal(b.doubleValue()));
        }
        throw new IllegalArgumentException("No valid big decimal translation for " + b.getClass());
    }

    public static Integer add(Integer a, Number b) {
        return a + b.intValue();
    }

    public static Long add(Long a, Number b) {
        return a + b.longValue();
    }

    public static Float add(Float a, Number b) {
        return a + b.floatValue();
    }

    public static Double add(Double a, Number b) {
        return a + b.doubleValue();
    }
}
如果这是作为静态方法实现的,那么可以使用静态导入

import static mixins.Numbers.*;

public class Example {

    public static void main(String[] args) {
        BigDecimal fortytwo = new BigDecimal(42);
        BigDecimal fiftyfive = add(fortytwo, 13);
        System.out.println(fiftyfive);
    }

}

实际上,我已经在一个通用的“实数”类(称为“Value”)上工作了一段时间,但更多的是作为一个设计练习;我也明白为什么没有早点完成

首先,你必须要有一些基本的规则来使用-我选择使用Java FP(IEEE-754)规则-这意味着你必须考虑像“无穷大”和“NaN”这样的结果,即使类型实际上不支持它们;事实证明,像互惠这样的事情非常棘手。但我正在到达那里,这是一个有趣的旅程

帮助我的一件事是,我很早就决定需要处理“身份”值——特别是0、1和-1,以及-0、+/-无穷大和NaN作为特例;原因是(例如)它们中的任何一个相乘通常根本不需要任何计算。 x*1=x,x*NaN=NaN,x*0=0(或NaN),x*+/-infinity=+/-infinity;除法、加法和减法也有类似的规则,这意味着你可以快速一致地消除大量的糟粕。 这使得实现者只需处理需要计算的情况